Bash

在 awk 中使用 shell 變數

  • January 31, 2022

這是我的腳本(查找包含指定模式的文件):

find . -type f \
   -exec awk -v vawk="$1" '/'"$vawk"'/ {c++} c>0 { print ARGV[1]; exit 0 } END { if (! c) {exit 1}}' \{\} \;

我想將我的腳本與參數 § 一起使用:

MyScript.sh pattern

我的問題是我無法將$1變數放入awk.

當我嘗試調試我的腳本時

bash -x MyScript.sh pattern

這是輸出:

+ find . -type f -exec awk -v vawk=pattern '// {c++} c>0 {print ARGV[1] ; exit 0 } END { if (! c) {exit 1}}' '{}' ';'

$vawk變數似乎為空。

任何想法?

您似乎混淆了 awk 變數和 shell 變數。 awk -v vawk="$1"創建一個名為 的awk變數vawk,但您正在嘗試使用shell語法 ( $vawk)。這不起作用,因為 shell 沒有名為vawk. 我想你想要的是

awk -v vawk="$1" '$0 ~ vawk { c++ } # ...'
#                      ^ awk variable syntax

這個現在關閉為重複的問題轉載,因為它包括關於 awk 變數傳遞的限制的警告,人們可能會覺得這很有用。

shell 變數就是這樣:一個shell變數。如果你想把它變成一個awk變數,你需要這樣的語法:

awk -v x="$x" '$2 == x {print $1}' infile

要麼

awk '$2 == x {print $1}' x="$x" infile

但是,它們會遇到一個問題:轉義序列在其中被擴展(在 GNU awk4.2 或更高版本中,如果$x以 開頭@/和結尾/,它被視為變數的正則表達式類型)。

因此,例如,如果 shell 變數包含兩個字元反斜杠n,則 awk 變數最終將包含換行符(在 gawk 4.2+ 中,如果它包含@/foo/,則 awk 變數將包含foo並且類型為regexp)。

另一種方法(但-v需要 POSIX awk 或 nawk (與 1970 年代的 awk 相比,仍然可以/bin/awk在 Solaris 中找到))是使用環境變數:

x="$x" awk '$2 == ENVIRON["x"] {print $1}' infile

另一種方法(仍然使用較新的 awk)是在 awk 中使用 ARGV 數組:

awk 'BEGIN {x = ARGV[1]; delete ARGV[1]}
 $2 == x {print $1}' "$x" infile

另請注意,無論您使用ARGV/ ENVIRON/-vvar=value參數,如果相應的字元串形狀像數字,則將其視為數字字元串(可辨識的數字格式的範圍因實現而異)。

這很重要,因為在上面的例子中,如果是例如or ,$2 == ENVIRON["VAR"]它將是一個字元串比較¹ ,但是如果它是or (或者可能, 取決於實現和版本),它將是一個數字比較,假設看起來也是數字的。所以,並且都被認為是平等的。$VAR``foo``1f2``1e2``1.1``inf``0xff``awk``$2``10.0e1``100``1e2

正在做:

awk 'BEGIN {var = "" ENVIRON["VAR"]}'

將確保var awk變數始終被視為字元串,即使$VARshell 變數看起來像一個數字。

awk 'BEGIN {var = 0 + ENVIRON["VAR"]}'

將其轉換為數字(至少可以解釋為數字的前導部分)。


¹或strcoll()與某些實現進行比較(POSIX曾經要求),也就是說,a == b如果其中一個ab兩個是字元串,則如果a並且b具有相同的排序順序,則返回true。

引用自:https://unix.stackexchange.com/questions/50044