awk とシェルとの値の受け渡しについて

# 概要

awk への値の受け渡しの記事はよく見かけるが
awk からシェルへの値の受け渡しの記事が少ないのでまとめてみた。

## シェルから awk への値の受け渡し

awk への値の受け渡しは -v オプションを使うと覚えておけば間違いない。

```sh:シェルからawkへの値の受け渡し
#!/bin/sh

# -v オプションで値を手入力
echo | awk -v foo=before '{print foo}'
# 実行結果: before

# 後ろには書けない
echo | awk '{print foo}' -v foo=after
# 実行結果: awk: fatal: cannot open file `-v' for reading (No such file or directory)

# -v 無しで渡す方法もあるが、BEGINブロックで値を参照できない
echo | awk 'BEGIN{print foo} {print foo} END{print foo}' foo="Not an option"
# 実行結果:
# 実行結果: Not an option
# 実行結果: Not an option
# -v オプションを使うほうが望ましい
echo | awk -v foo="This is an option" 'BEGIN{print foo} {print foo} END{print foo}'
# 実行結果: This is an option
# 実行結果: This is an option
# 実行結果: This is an option

# 複数指定できる
echo | awk -v foo=first -v bar=second '{print foo, bar}'
# 実行結果: first second

# 変数の値を渡すこともできる
hoge="hello"
fuga="world"
echo | awk -v foo=${hoge} -v bar="$fuga" '{print foo, bar}'
# 実行結果: hello world

# コマンドの実行結果を渡すこともできる
echo | awk -v foo="$( echo 'hello world' | sed -e 's/world/japan/' )" '{ print foo }'
# 実行結果: hello japan

# パイプとの組み合わせ
echo "world" | awk -v foo="hello" '{ bar=foo FS $0; print bar }' | echo -e $(cat)
# 実行結果: hello world

# awk のスクリプト内に直接書く
hoge="hello"
fuga="world"
echo | awk 'BEGIN {print "'"$hoge"'","'"$fuga"'"}'
# 実行結果: hello world

# 文字列のリダイレクト
hoge="hello world"
echo | awk '{print $0}' <<< "$hoge"
# 実行結果: hello world
```

参照：
[awkコマンドへ値を渡す手法のまとめ](https://qiita.com/gin_135/items/39baa6426cb342d3370f)
[awkからシェル変数を参照する](https://qiita.com/tkykmw/items/1622970830262355a5a3)
[How do I use shell variables in an awk script?](https://stackoverflow.com/questions/19075671/how-do-i-use-shell-variables-in-an-awk-script)


## awk からシェルへの値の受け渡し

単一なら $() で代入、
複数なら read で代入が分かりやすい。

```sh:awkからシェルへの値の受け渡し
#!/bin/sh

# awk の出力値をバッククォートで囲い、変数に入れる
account_name=`awk -F@ '{print $1}' <<< "account1@domain.com"`
echo ${account_name}
# 実行結果: account1

# 以下も同じく awk の出力値を $() を使って変数に入れる。
account_name=$(awk -F@ '{print $1}' <<< "account2@domain.com")
echo ${account_name}
# 実行結果: account2

# awk の出力を eval で評価する
eval `awk -F@ '{ printf("account_name=\"%s\" ; domain_name=\"%s\"",$1,$2) }' <<< "account3@domain.com"`
echo ${account_name}
echo ${domain_name}
# 実行結果: account3
# 実行結果: domain.com

# 以下も同じ
eval $(awk -F@ '{ printf("account_name=\"%s\" ; domain_name=\"%s\"",$1,$2) }' <<< "account4@domain.com")
echo ${account_name}
echo ${domain_name}
# 実行結果: account4
# 実行結果: domain.com

# set コマンドにて位置パラメータに一旦渡し、それを参照する
set $(awk -F@ '{print $1, $2}' <<< "account5@domain.com")
account_name=$1
domain_name=$2
echo ${account_name}
echo ${domain_name}
# 実行結果: account5
# 実行結果: domain.com

# awk の出力値をreadを使って変数に入れる
read account_name domain_name <<< $( awk -F@ '{print $1, $2}' <<< "account6@domain.com" )
echo ${account_name}
echo ${domain_name}
# 実行結果: account6
# 実行結果: domain.com

# 配列への格納
declare -a array=()
mapfile -t array <<< $( awk -F@ '{print $1, $2}' <<< "account7@domain.com" )
echo "${array[@]}"
# 実行結果: account7 domain.com
```

以下は <() を使っているので bash でないと機能しない。

```bash:bashでないと機能しない
#!/bin/bash

# awk の出力を source で評価する
source <(awk -F@ '{ printf("account_name=\"%s\" ; domain_name=\"%s\"",$1,$2) }' <<< "account8@domain.com")
echo ${account_name}
echo ${domain_name}
# 実行結果: account8
# 実行結果: domain.com

# awk の出力値をreadを使って変数に入れる
read account_name domain_name < <( awk -F@ '{print $1, $2}' <<< "account9@domain.com" )
echo ${account_name}
echo ${domain_name}
# 実行結果: account9
# 実行結果: domain.com

# 配列への格納
declare -a array=()
mapfile -t array < <( awk -F@ '{print $1, $2}' <<< "account10@domain.com" )
echo "${array[@]}"
# 実行結果: account10 domain.com
```


参照：
[シェルのawk内で定義した変数や結果をAwk外で取り扱いたい](https://teratail.com/questions/38693)