我创建了以下脚本:
#!bin/bash
cat > Top10 <<EOF
Linux Mint 17.2
Ubuntu 15.10
Debian GNU/Linux 8.2
Mageria 5
Fedora 23
openSUSE Leap 42.1
Arch Linux
CentOS 7.2-1511
PCLinuxOS 2014.12
Slackware Linux 14.1
FreeBSD
EOF
sed -ri "s/^[^0-9]*$//" Top10
sed -r "s/(.*)([[:space:]][[:digit:]]*.*)$/\2\1/" Top10 | sed -r "s/([[:space:]])([[:digit:]])/\2/" | sed -r "s/([[:digit:]])([[:alpha:]])/\1 \2/" > Top10
sed -r -i "s/(.*)/\L\1/" Top10
sed -r -i "y/[aeiou]/[AEIOU]/" Top10
sort Top10 -g -o Top10
cat Top10
当我运行它几次时,发生了以下情况:
正如您所看到的,有时 Top10 文件是空的,有时它会变成我需要的样子。我知道从行尾到行首替换扩展名的命令做得不好。我在 VMware 虚拟机上运行了这个脚本。这可能是原因吗?
答案1
更具体地说,管道不是确定性的。
即在如下管道中:
command1 file | command2 | command3 >file
不能保证command1 file
在之前执行command3 >file
。
command1 file
因此和之间的竞争条件command3 >file
使得有时文件首先被读取command1 file
,有时文件首先被截断command3 >file
,在第一种情况下给出预期的输出,在第二种情况下给出空输出。
可以通过使用sponge
(在moreutils
包中)将输出写入文件来解决此问题,以确保仅在管道的其余部分执行完成后才将输出写入文件:
command1 file | command2 | command3 | sponge file
答案2
sed -r "s/(.*)([[:space:]][[:digit:]]*.*)$/\2\1/" Top10 | sed -r "s/([[:space:]])([[:digit:]])/\2/" | sed -r "s/([[:digit:]])([[:alpha:]])/\1 \2/" > Top10
导致文件首先被覆盖> Top10
,然后才被处理sed
(此时文件为空)
答案3
如果只需一个命令就可以完成,那么没有必要运行 6 个 sed 命令:
sed -ri 's/^[^0-9]*$//; s/(.*)/\L\1/; y/[aeiou]/[AEIOU]/; s/(.*)([[:space:]])([[:digit:]]*.*)$/\3 \1/' Top10
特别要注意,如果您只是以不同的方式对匹配项进行分组,那么第二个 sed 命令管道可以组合成一个表达式。由于您无论如何都想丢弃前导空格,然后在版本后添加一个空格,因此您可以在原始匹配项中执行此操作,方法是分别对前导空格和版本进行分组。