AWK内でbashシェル関数を使用する

AWK内でbash関数を何らかの方法で使用することは可能ですか?

サンプルファイル(string、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 

回答

system()関数を使用します:

awk "{printf("%s ",$1); system("d2h " $2)}" file 

この場合、systemd2h 247808を呼び出してから、このコマンドの出力をprintf出力に追加します:

Mike 3C800 

編集:

systembashshを使用します/ div> .bashrcにアクセスする方法が見つかりません。ただし、現在のbashスクリプトの関数を引き続き使用できます:

#!/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 

編集2:

わからないなぜですが、これは私のUbuntu16.04では機能しません。これは、Ubuntu 14.04で機能していたため、奇妙です。

コメント

  • d2hは実行可能ファイルでしたが、.bashrcまたはシェルスクリプトのいずれかで定義された’ “関数の場合はそうではありません”。
  • @MichaelHomerはい、その通りです。あなたのコメントのおかげで、私は誰も尋ねなかった質問に答えたことに気づきました。しかし、現在のスクリプトから(そしておそらくsourceを介して他のスクリプトから)関数を使用する方法を見つけましたが、’ f図はできます’が.bashrcで機能しない理由を説明します。
  • その’ $2のコンテンツがシェルコードとして解釈されるため、div>もコマンドインジェクションの脆弱性です。
  • export -f d2hは機能しません’ ksh / zshのように機能します:(\ 42と\ 47は単純な二重引用符のエスケープコードです)CODE=$(typeset -f d2h) awk ' { system("bash -c \47eval \42$CODE\42; d2h \42"$2"\42\47") }'

回答

awkからbashを呼び出して、その出力を使用できます。それが頻繁に発生する場合、パフォーマンスの観点からは明らかに危険です。マニュアルページの引用:

command | getline [var] 

出力を$ 0またはvarにパイプするコマンドを実行します

コマンドは、関数定義を含み、関数を実行するbashスクリプトになります。

回答

10進数から16進数への変換は、awkがそれ自体で非常にうまくできることです。そして、それを行うために awk 関数を定義することができます:

 function d2h(d) { return sprintf("%x", d) }  

ここで、awkbash関数の場合、bashシェルを実行するにはawkが必要です。bashその関数の定義を解釈し、awkによって抽出された値を引数として渡してその関数を呼び出します。

簡単ではありません。

bashは、環境を介した関数のエクスポートをサポートしているため、bashの後続の呼び出しで使用できるため、これが1つの方法です。 awkによって呼び出されるbashに対する関数の定義:

export -f d2h 

awkがコマンドを実行する唯一の方法(bash h ere)は、system("cmd")、またはprint... | "cmd"または"cmd" | getlineを使用します。いずれの場合も、awkはシェルを実行してcmdを解釈しますが、shbashではありません。したがって、bashを解釈するbash呼び出しであるshのコマンドラインを作成する必要があります。関数を呼び出すためのdiv>コマンドライン。引用符に注意する必要があります。

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))}" 

関数の出力を

の場合、パイプを介して転送する必要があります。そのためには、iv id = “の代わりにcmd | getlineを使用します。 4be2d082e4 “> (cmdのstdoutはそのままになります)。

cmd | getline line 1行を格納します(厳密に言えば 1レコード、デフォルトではレコードは行です)。複数行で構成されている場合に出力全体を取得するには、次のようなループが必要です。

 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 ..."  

つまり、関数の呼び出しごとに1つのshと1つのbashを実行します。 、そのため、非常に非効率的になります。これは、bashwhile read loopを使用して読み取りと分割を行わせるよりも、はるかに非効率的になります。

(unset -v IFS; while read -r a b rest; do printf "%s\n" "$a" d2h "$b" done < file) 

また、shellshock以降、bashBASH_FUNC_d2h%%mkshおよび新しいバージョンのdash 削除を含む一部のsh実装>環境からのこれらの環境変数:

$ 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) ..."  

回答

これを試してください:

awk "{print $1 ; printf "%x\n", $2}" file 

AFAIK、bashは使用できませんawkで関数を使用しますが、スクリプトのみです。必要に応じてawk関数を使用できます。

回答

ユーザー定義のbash関数を使用するInside awk

免責事項:これは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 

コメント

  • Iクイーンズを代表し、ブルックリンで育ちました

回答

@HaukeLagingのデモンストレーションの簡単な例command|getline

  1. 入力を次のようにします:
Dear friends my name is `id -nu` and today is `date "+%Y-%m-%d"`. 

シェル構文に従っている場合、入力では

`command` 

は、次の結果に置き換えられるインラインコマンドを示すために使用されます。彼の実行。

  1. インラインシェルコマンドは、次の方法で展開できます。
#!/usr/bin/gawk -f BEGIN { FS ="`"; } NF==3 { $2 | getline $2 } { print } 
  1. 使用法(通常のchmodの後):
$ expand-inline input Dear friends my name is jjoao and today is 2018-01-15. 

回答

これによりチャンスが生まれます。

cat ../logs/em2.log.1 |grep -i 192.168.21.15 |awk "{system("date"); print $1}" 

システム関数を使用すると、awkストリーム内でbashコマンドを解析できます。

回答

GNU awkの場合、この回答ですが、他のバージョンでも同じトリックが実装されている可能性があります。パイプの右側がまったく同じで出てこない限り、awkはパイプを閉じないという考え方です。しかし、それが異なる場合は、新しいパイプが開きます。たとえば、次のように入力した場合:

awk "BEGIN{ shell= "/bin/bash" } { print $0 | "/bin/bash" } END { print "echo $a" | " /bin/bash" }" 

次のように入力できます:

a=5 echo $a 

および期待される(?)応答を取得します5:新しいシェルは生成されませんでした。しかし、ENDセクションで余分なスペースを入力したため、パイプのRHSが異なり、変数aの値がない新しいシェルが生成されます(したがって、終了時に空白行が出力されます。ドキュメントですが、長期パイプを使用するための推奨される方法は、私が持っているとおりです。コマンドを変数のBEGINセクションに配置し、その変数を再利用します。

ユーザー定義関数をbashセッションに与えてその後、それを再利用することは、読者に残された演習です:)

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です