下面的脚本是我在RHEL 5上构建的,它运行得很好。然而,现在我正在各种RHEL6和Ubuntu上进行测试,并且这个消息是一致的,“太多了”。任何关于发生什么的想法。这是我正在编写的脚本。
$ echo "HOST,UserName,IsDiabled,PassLastSet" > fileIWantToWriteTo;
$ ( echo "foreach user ( `cut -d':' -f'1' /etc/passwd` )";
echo "sudo passwd -S "\$"user" ; echo "end"
) | csh |
sed 's/ /,/g' | cut -f1-3 -d',' |
sed 's/LK/DISABLED/' |
sed 's/PS/ENABLED/' |
awk 'BEGIN{"hostname" | getline hstnm ; }{print hstnm "," $0}' \
>> fileIWantToWriteTo现在,我正在各种Linux操作系统上测试这一点,并得到以下输出消息
# ( echo "foreach user ( `cut -d':' -f'1' /etc/passwd` )"
echo "sudo passwd -S "\$"user" ; echo "end" ) |
csh |
sed 's/ /,/g' |
cut -f1-3 -d',' |
sed 's/LK/DISABLED/' |
sed 's/PS/ENABLED/' |
awk 'BEGIN{"hostname" | getline hstnm ; }; {print hstnm "," $0}'
Too many ('s.然而,当我测试的时候,我取得了成功。
# ( echo "foreach user ( `cut -d':' -f'1' /etc/passwd` )"
echo "sudo passwd -S "\$"user" ; echo "end" ) |
csh |
sed 's/ /,/g' |
cut -f1-3 -d',' |
sed 's/LK/DISABLED/' |
sed 's/PS/ENABLED/' |
awk 'BEGIN{"hostname" | getline hstnm ; }; {print hstnm "," $0}'
tophostd,root,ENABLED,2015-08-31 tophostd,bin,DISABLED,2013-08-19发布于 2016-05-24 05:37:38
我的猜测是,在测试命令行时,列表中只有一个用户id。这一猜测背后的理由是一个小小的离题。
简化脚本
使用bash创建一个向csh发送的复合命令,让我觉得要么是故意的混淆,要么是奇怪的过度思考。而不是不工作
( echo "foreach user ( `cut -d':' -f'1' /etc/passwd` )"
echo "sudo passwd -S "\$"user" ; echo "end"
) | csh |
# ...你可以这么做:
for user in $(cut -d: -f1 /etc/passwd); do
sudo passwd -S $user
done根本不需要csh,而且阅读起来也容易得多。再加上它能用。(它确实假定没有任何用户名包含空格或glob字符。)
更简单的是
sudo passwd -Sa生成所有帐户的状态信息。(假设您的passwd实现了该选项。)
另外:
sed 's/ /,/g' | cut -d, -f1-3可能会更易读
cut -f1-3 --output-delimiter=,两个编辑
sed 's/LK/DISABLED/' | sed 's/PS/ENABLED/' 可以放在一个命令中:
sed 's/LK/DISABLED/;s/PS/ENABLED/'还可以使用sed插入前缀。
hostname=$(hostname)
sed "s/^/$hostname,/;s/LK/DISABLED/;s/PS/ENABLED/"所以最终的结果是
hostname=$(hostname)
sudo passwd -Sa |
cut -d' ' --output-delimiter=, -f1-3 |
sed "s/^/$hostname,/;s/LK/DISABLED/;s/PS/ENABLED/"在我看来更直截了当。或者,您可以使用awk而不是cut+sed
sudo passwd -Sa |
awk -v hostname="$(hostname)" \
'{ sub(/LK/, "DISABLED", $2);
sub(/PS/, "ENABLED", $2);
printf "%s,%s,%s,%s\n", hostname, $1, $2, $3;
}'但回到问题上
总之,您的脚本失败的原因是:
csh对于命令格式非常具体。它不允许在意想不到的地方换行。foreach语句的语法精确地是:
foreach <var> ( <list> )
<commands>
end<list>中不能有换行符(除非用反斜杠将它们转义)。
现在,当您要求bash执行一个命令时,使用$(command [args...]) (或不建议使用的回勾符号`command [args...]`,您确实应该停止使用):(重点添加)
Bash通过执行命令并将命令替换为命令的标准输出来执行扩展,并删除所有尾随的换行符。
因此,如果命令返回一行,则将有一个尾尾换行符,并将其删除:
$ echo "foreach i ( $(seq 1) )"
foreach i ( 1 )但是,如果有多行,您将得到内部换行符:
$ echo "foreach i ( $(seq 1 2) )"
foreach i ( 1
2 )其中的第一个会很好。但如果你把第二条信息输入csh,它就会抱怨说“太多了”这条信息有点神秘。
您可以通过分词来消除内部换行符,这意味着不使用引号。(不过,您仍然需要引用括号。)
$ echo foreach i \( $(seq 1 2) \)
foreach i ( 1 2 )但是,您需要确保在替换中没有glob元字符,因为未引用的替换也会扩展globs。总的来说,我将坚持这个答案的第一部分中概述的方法,并避免将命令组装到另一个shell的困难。
https://stackoverflow.com/questions/37403607
复制相似问题