一段时间以来我一直在试图寻找这个问题的答案。我正在编写一个快速脚本来运行基于 awk 输出的命令。
ID_minimum=1000
for f in /etc/passwd;
do
awk -F: -vID=$ID_minimum '$3>=1000 && $1!="nfsnobody" { print "xfs_quota -x -c 'limit bsoft=5g bhard=6g $1' /home "}' $f;
done
问题是该-c
参数采用单引号中的命令,我不知道如何正确地转义它,而且它也$1
不会扩展到用户名中。
本质上我只是想让它输出:
xfs_quota -x -c 'limit bsoft=5g bhard=6g userone' /home
xfs_quota -x -c 'limit bsoft=5g bhard=6g usertwo' /home
ETC...
答案1
xfs_quota -x -c 'limit bsoft=5g bhard=6g USER' /home
要为每个USER
UID 至少为 的用户运行该命令$ID_minimum
,请考虑首先解析这些用户,然后再实际解析跑步命令,而不是尝试创建表示要运行的命令的字符串。
如果您创建了命令字符串,则必须创建eval
它。这很繁琐而且很容易出错。最好只获取用户名列表,然后运行命令。
getent passwd |
awk -F: -v min="${ID_minimum:-1000}" '$3 >= min && $1 != "nfsnobody" { print $1 }' |
while IFS= read -r user; do
xfs_quota -x -c "limit bsoft=5g bhard=6g $user" /home
done
请注意,实际上并不需要单身的后面的论证周围引用了引号-c
。这里我使用双引号,因为我希望 shell 展开$user
包含由 提取的值的变量awk
。
我在为命令中的变量${ID_minimum:-1000}
赋予值时使用。这将扩展到 的值,或者如果该变量为空或未设置,则扩展到 。min
awk
$ID_minimum
1000
如果你真的如果愿意,您可以使上面的循环打印出命令而不是执行它们:
getent passwd |
awk -F: -v min="${ID_minimum:-1000}" '$3 >= min && $1 != "nfsnobody" { print $1 }' |
while IFS= read -r user; do
printf 'xfs_quota -x -c "limit bsoft=5g bhard=6g %s" /home\n' "$user"
done
eval
再次注意,如果您要使用或通过其他方式执行生成的命令,在输出的命令字符串中使用双引号(而不是单引号)不会以任何方式混淆 shell 。如果它困扰您,只需将上面第一个参数中的单引号和双引号交换即可printf
。
答案2
for f in /etc/passwd;
这有点愚蠢,因为实际上不存在只有一个值的循环。
但问题似乎是从 awk 打印单引号。您可以在 shell 中转义它们,但也可以在 awk 中使用反斜杠转义来打印它们。是有数值的字符\OOO
面向对象(在八进制),也是\047
如此'
。所以这是一种方法:
awk -F: -vID=$ID_minimum '$3>=1000 && $1!="nfsnobody" {
printf "xfs_quota -x -c \047limit bsoft=5g bhard=6g %s\047 /home\n", $1}' /etc/passwd
您可以在十六进制中使用类似的转义,\x27
但如果以下字符是有效的十六进制数字,则在某些实现中可能会被误解。 (当然,我假设是 ASCII 或 ASCII 兼容的字符集,例如 UTF-8。)
答案3
使用-f -
awk 的选项从 stdin 和此处文档获取脚本:
awk -F: -v "ID=$ID_minimum" -f - <<'EOT' /etc/passwd
$3>=1000 && $1!="nfsnobody" {
print "xfs_quota -x -c 'limit bsoft=5g bhard=6g "$1"' /home "
}
EOT
答案4
这是一个可怕的障碍,但它又快又容易......
awk -F: -vQ="'" -vID=$ID_minimum '$3>=1000 && $1!="nfsnobody" { print "xfs_quota -x -c " Q "limit bsoft=5g bhard=6g $1" Q " /home "}' $f;