不知怎的,我创建了一个非确定性的 sh 脚本

不知怎的,我创建了一个非确定性的 sh 脚本

我创建了以下脚本:

#!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 命令管道可以组合成一个表达式。由于您无论如何都想丢弃前导空格,然后在版本后添加一个空格,因此您可以在原始匹配项中执行此操作,方法是分别对前导空格和版本进行分组。

相关内容