我有一個文件user-pid.out2
,其中有“用戶號”和“進程 ID”作為兩列。根據usernumber我想找對應的進程id。下面的前兩行沒有顯示正確的輸出,但是當我在第 3 行和第 4 行中將用戶硬編碼為 62 時,它顯示了與用戶 62 相對應的進程 ID。
USR=62
usrpid=`awk '$1 == "$USR" {print $2}' /home/hu/batchhu/dbscripts_tst2/user-pid.out2`
echo "first:" $USR $usrpid
# This shows 62 and blank for process id
usrpid=`awk '$1 == "62" {print $2}' /home/hu/batchhu/dbscripts_tst2/user-pid.out2`
echo "second:" $USR $usrpid
# This shows 62 and process id corresponding to this user in the file user-pid.out2
答案1
@artm 展示了一種雙引號 awk 腳本並轉義各種字符的技術。這裡還有另外 3 種技巧
跳出單引號讓shell擴展變數
usrpid=$(awk '$1 == "'"$USR"'" {print $2}' file)
將 shell 變數傳遞給 awk 變數
usrpid=$(awk -v usr="$USR" '$1 == usr {print $2}' file)
如果變數是導出的,則使用awk的ENVIRON數組
usrpid=$(awk '$1 == ENVIRON["USR"] {print $2}' file)
後者應該是首選。
在第一種方法中,就像 @artm 的方法一樣,shell 變數的內容嵌入到程式碼中awk
,這樣就變成了命令注入漏洞如果變數的內容沒有受到嚴格控制(例如, with USR='blah" || system("reboot") || "'
,則會呼叫reboot
)。
第二個不會引入命令注入漏洞,但如果$USR
包含反斜線字符,則該變數將不會包含與shell 變數usr
awk
相同的內容,因為其中會擴展類似 C 的反斜線轉義序列。$USR
awk
使用ENVIRON
就沒有這些問題。
答案2
第一個範例中的the"$USR"
未展開,因為它出現在單引號字串內'$1 == "$USR" { print $2 }'
,因此此程式碼正在尋找第一列為「$USR」而不是 62 的行。
以下應該有效:
usrpid=$(awk "\$1 == \"$USR\" {print \$2}" /home/hu/batchhu/dbscripts_tst2/user-pid.out2)
變化:
- awk 命令列使用雙引號,因此 $USR 被擴展
- awk 程式中的美元符號和引號字元被轉義
$()
使用而不是反引號所以反斜線處理正確
請注意,由於 的值USR
是直接插值到 awk 腳本中的,因此只有當該值僅包含 awk 將按字面解釋的字符時它才有效:如果$USR
包含\
或"
,則一切都會崩潰 - "
將是awk 字符串文字的結尾,並\
引用下一個字元。