我使用以下脚本在几百个Solaris(v9,10,11)和Red Hat Enterprise Linux(v5,6,7)服务器上检索有关已安装文件系统的信息以供分析。
# retrieves for all mounted file-systems: server, device, allocated, used, available, percent_used, mount_directory, permissions, owner_name, and group_name
server=$(uname -n)
df -h | awk '
NF == 6 { print ($0); }
NF == 1 { device = $1; }
NF == 5 { print (device, " ", $0); }
' | while read device allocated used available percent mount
do
ls -ld "${mount}" | read permissions links owner_name group_name size month day time directory
echo "${server} ${device} ${allocated} ${used} ${available} ${percent} ${mount} ${permissions} ${owner_name} ${group_name}"
done
我使用PuTTY“plink”实用程序从Windoze执行此操作。
plink -m filesys.script server_name >>filesys.txt
所有工作都按预期工作,直到我的默认shell在所有服务器上从ksh更改为bash。现在,获取权限,owner_name和group_name的ls输出的第二个读取命令不起作用,也不会产生任何错误消息。因此,结果是输出中只有七个令牌(服务器到挂载),并且没有用于permissions,owner_name或group_name的任何内容。
我已经确认,如果我将脚本上传到带有shebang(#!/ bin / ksh)的Unix服务器,则脚本按预期工作。但是,我不想将此脚本推送到数百台服务器并将脚本维护在分布式机制中。我想保留中央Windoze工作站上的脚本,并使用plink的-m参数调用。将shabang放在文件顶部不会使用plink -m选项执行ksh。
正在播放的Bash shell版本是3.2和4.1。我还确定Windoze脚本文件已删除回车符。 awk实用程序用于处理设备名称太长而df将输出分成两行的情况。
同样,第一次读取(来自df / awk)工作正常,但第二次(ls输出)却没有。我通过在第二次读取后放置一个'set'来确认,那些环境变量不在环境中。
答案 0 :(得分:2)
read
(作为管道元素)发生在子shell中,因此即使它实际上 完美地执行,一旦该管道退出其结果也不可用于echo
在一个单独的行上运行(作为最初生成管道的父进程的一部分)。这是POSIX完全允许的;管道的哪个组件(如果有的话)由生成的管道执行,该管道未由标准指定,因此是实现定义的。
您可以将echo
置于与read
相同的管道元素内来解决此问题:
server=$(uname -n)
df -h | awk '
NF == 6 { print ($0); }
NF == 1 { device = $1; }
NF == 5 { print (device, " ", $0); }
' | while read device allocated used available percent mount
do
# NOTE: parsing output from "ls" is unreliable
ls -ld "${mount}" | {
read permissions links owner_name group_name size month day time directory
echo "${server} ${device} ${allocated} ${used} ${available} ${percent} ${mount} ${permissions} ${owner_name} ${group_name}"
}
done
参考文献:
如果您有GNU stat
或find
,其中任何一个都允许您提供格式字符串来控制元数据输出,我强烈建议使用它们代替ls -l
进行解析元数据。即使perl
在某种程度上更好,只有一个普遍可用的实现在发布版之间具有统一的stat
行为。