![环境变量未在命令行参数内展开](https://linux22.com/image/57706/%E7%8E%AF%E5%A2%83%E5%8F%98%E9%87%8F%E6%9C%AA%E5%9C%A8%E5%91%BD%E4%BB%A4%E8%A1%8C%E5%8F%82%E6%95%B0%E5%86%85%E5%B1%95%E5%BC%80.png)
我有一个文件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 字符串文字的结尾,并\
引用下一个字符。