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
この場合、system
はd2h 247808
を呼び出してから、このコマンドの出力をprintf
出力に追加します:
Mike 3C800
編集:
system
はbash
shを使用します/ 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で機能していたため、奇妙です。
コメント
回答
awkからbashを呼び出して、その出力を使用できます。それが頻繁に発生する場合、パフォーマンスの観点からは明らかに危険です。マニュアルページの引用:
command | getline [var]
出力を$ 0またはvarにパイプするコマンドを実行します
コマンドは、関数定義を含み、関数を実行するbashスクリプトになります。
回答
10進数から16進数への変換は、awk
がそれ自体で非常にうまくできることです。そして、それを行うために awk
関数を定義することができます:
function d2h(d) { return sprintf("%x", d) }
ここで、awk
がbash
関数の場合、bash
シェルを実行するにはawk
が必要です。bash
その関数の定義を解釈し、awk
によって抽出された値を引数として渡してその関数を呼び出します。
簡単ではありません。
bash
は、環境を介した関数のエクスポートをサポートしているため、bash
の後続の呼び出しで使用できるため、これが1つの方法です。 awk
によって呼び出されるbash
に対する関数の定義:
export -f d2h
awk
がコマンドを実行する唯一の方法(bash
h ere)は、system("cmd")
、またはprint... | "cmd"
または"cmd" | getline
を使用します。いずれの場合も、awk
はシェルを実行してcmd
を解釈しますが、sh
、bash
ではありません。したがって、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
を実行します。 、そのため、非常に非効率的になります。これは、bash
にwhile read loop
を使用して読み取りと分割を行わせるよりも、はるかに非効率的になります。
(unset -v IFS; while read -r a b rest; do printf "%s\n" "$a" d2h "$b" done < file)
また、shellshock以降、bash
はBASH_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
:
- 入力を次のようにします:
Dear friends my name is `id -nu` and today is `date "+%Y-%m-%d"`.
シェル構文に従っている場合、入力では
`command`
は、次の結果に置き換えられるインラインコマンドを示すために使用されます。彼の実行。
- インラインシェルコマンドは、次の方法で展開できます。
#!/usr/bin/gawk -f BEGIN { FS ="`"; } NF==3 { $2 | getline $2 } { print }
- 使用法(通常の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セッションに与えてその後、それを再利用することは、読者に残された演習です:)
d2h
は実行可能ファイルでしたが、.bashrcまたはシェルスクリプトのいずれかで定義された’ “関数の場合はそうではありません”。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") }'