我在RHEL 5上构建的以下脚本运行正常。但是现在我正在测试各种RHEL6和Ubuntu并且消息是一致的“太多('s。)。任何关于发生了什么的想法。这是我正在处理的脚本
$ 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
答案 0 :(得分:3)
我的猜测是,当您测试该命令行时,列表中只有一个用户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,而且阅读起来也更容易。加上它有效。 (它假设没有用户名包含空格或全局字符。)
更简单的是
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
,它会抱怨一些有点神秘的信息“太多了(.s。”。
您可以通过对行进行分词来消除内部换行符,这意味着不使用引号。 (但你仍然需要引用括号。)
$ echo foreach i \( $(seq 1 2) \)
foreach i ( 1 2 )
您需要确保替换中没有glob元字符,因为未引用的替换也会扩展globs。总的来说,我会坚持使用本答案第一部分中概述的方法,并避免将命令组合传递给另一个shell的困难。