AWKでbash機能を使用できますか?
サンプルファイル(文字列、int、int、int)
Mike 247808 247809 247810
値を10進数から16進数に変換してみてください。
シェルスクリプトの内部または内部で定義された関数です.bashrc
。
$ awk '{print $1 ; d2h($2)}' file
awk: calling undefined function d2h
input record number 1, file file
source line number 1
答え1
次の機能を試してくださいsystem()
。
awk '{printf("%s ",$1); system("d2h " $2)}' file
あなたの場合、コマンドの出力がsystem
呼び出され、d2h 247808
次にprintf
出力に追加されます。
Mike 3C800
編集する:
system
代わりに、私はそれにアクセスする方法を見つけることができsh
ません。しかし、現在bashスクリプトの機能を引き続き使用できます。bash
.bashrc
#!/bin/bash
d2h() {
# do some cool conversion here
echo "$1" # or just output the first parameter
}
export -f d2h
awk '{printf("%s ",$1); system("bash -c '\''d2h "$2"'\''")}' file
注:-f
次の目的で使用されています関数のエクスポート変数ではありません。
編集2:
理由はわかりませんが、Ubuntu 16.04では機能しません。 Ubuntu 14.04で実行されたので、これは奇妙です。
答え2
awkでbashを呼び出し、その出力を使用できます。パフォーマンスの観点からは、このようなことがあまりにも頻繁に発生する場合、明らかに危険です。マニュアルページを引用すると、次のようになります。
command | getline [var]
コマンドを実行して、出力を$ 0またはvarにパイプします。
コマンドは、関数定義を含み、その関数を実行するbashスクリプトです。
答え3
10進数から16進数への変換は、それawk
自体でうまく実行できます。以下を定義できます。awk
これを行う関数:
function d2h(d) {
return sprintf("%x", d)
}
awk
一般的な質問に答えるには、関数を実行するには、関数の定義を解釈し、抽出された値を引数として渡す関数を呼び出すシェルを実行する必要がありますbash
。awk
bash
bash
awk
些細なことではありません。
bash
後続の呼び出しで使用できるように環境を介して関数をエクスポートする機能がサポートされているため、これは呼び出し側にbash
関数定義を渡す方法の1つです。bash
awk
export -f d2h
awk
(ここで)コマンドを実行する唯一の方法は、対応する、またはbash
を使用することです。すべての場合において、シェルはそれを解釈するために実行されますが、代わりになります。したがって、関数を呼び出すためにコマンドラインを解釈する呼び出しであるコマンドラインを作成する必要があるため、引用に注意する必要があります。system("cmd")
print... | "cmd"
"cmd" | getline
awk
cmd
sh
bash
sh
bash
bash
export -f d2h
<file awk -v q="'" '
function shquote(s) {
gsub(q, q "\\" q q, s)
return q s q
}
{print $1; system("exec bash -c '\''d2h \"$1\"'\'' bash " shquote($2))}'
関数の出力を再インポートするには、awk
再パイプする必要があります。これを行うには、cmd | getline
代わりに使用できますsystem(cmd)
(cmd
標準出力は変更されません)。
cmd | getline line
お店一行(厳密に言えば、記録、基本的に行として書き込む)、複数行で構成されている場合、全体の出力を取得するには、次のループが必要です。
awk '...
cmd = "exec bash -c '\''d2h \"$1\"'\'' bash " shquote($2)
output = ""
while ((cmd | getline line) > 0) {
output = output line RS
}
sub(RS "$", "", output) # remove the last newline
...'
つまり、関数が呼び出されるたびに順番に実行する必要があるため、sh
非常に非効率的です。bash
これは、以下をbash
使用して読み取りおよび分割するよりもはるかに効率的ではありませんwhile read loop
。
(unset -v IFS; while read -r a b rest; do
printf '%s\n' "$a"
d2h "$b"
done < file)
bash
また、Shellshock関数は現在という名前の環境変数としてエクスポートされますBASH_FUNC_d2h%%
。一部のsh
実装にはmksh
最新バージョンが含まれています。dash
削除する環境の対応する環境変数は次のとおりです。
$ env 'foo%%=bar' dash -c 'printenv foo%%'
$ env 'foo%%=bar' mksh -c 'printenv foo%%'
$ env 'foo%%=bar' zsh -c 'printenv foo%%'
bar
$ env 'foo%%=bar' bash -c 'printenv foo%%'
bar
したがって、脆弱な関数エクスポート機能に依存するのではなく、他の手段を介して関数定義を渡すことができます。一般的に使用される名前の環境変数で使用できます。
BASH_FUNCTIONS=$(typeset -f d2h) awk '
...
cmd = "exec bash -c '\''eval \"$BASH_FUNCTIONS\";" \
"d2h \"$1\"'\'' bash " shquote($2)
...'
答え4
awkでカスタムbash関数を使用する
婦人声明:私はこれがOPが望んでいなかったことを知っていますが、Googleは私のような他の人をこの答えに導きます。
状態
自分や[ほとんどの]同僚が嫌いではないため、機能別に構成されたスクリプトがあり、そのbash
機能の少なくとも1つはawk
。
解決策
スクリプト
#!/bin/env bash
# The main function - it's a sound pattern even in BASH
main(){
# In the awk command I do some tricky things with single quotes. Count carefully...
# The first $0 is outside the single quotes so it is the name of the current bash script.
# The second $0 is inside the single quotes so it is awk's current line of input.
awk '{printf("%s. ", ++c); system("'$0' --do"); print $0}'<<-PRETEND_THIS_IS_AN_INPUT_STREAM
and
and
well
PRETEND_THIS_IS_AN_INPUT_STREAM
}
# functionized to keep things DRY
doit(){
echo -n "doin' it "
}
# check for a command switch and call different functionality if it is found
if [[ $# -eq 1 && $1 == "--do" ]];
then
doit
else
main
fi
出力
$ ./example.sh
1. doin' it and
2. doin' it and
3. doin' it well