这个脚本有时候会失败,有时候会成功(非常烦人的情况):
#!/bin/bash
set -Eeuxo pipefail
test_dir="$(mktemp -d)"
touch "$test_dir/file"{001..312}
latest_file="$(find $test_dir -type f | sort -r | head -n1)"
echo $latest_file
当成功时,它会记录如下内容:
++ mktemp -d
+ test_dir=/tmp/tmp.yWelcpBYB7
+ touch /tmp/tmp.yWelcpBYB7/file001 /tmp/tmp.yWelcpBYB7/file002 ... /tmp/tmp.yWelcpBYB7/file312
++ find /tmp/tmp.yWelcpBYB7 -type f
++ head -n1
++ sort -r
+ latest_file=/tmp/tmp.yWelcpBYB7/file312
+ echo /tmp/tmp.yWelcpBYB7/file312
/tmp/tmp.yWelcpBYB7/file312
当它失败时,它会记录如下内容:
++ mktemp -d
+ test_dir=/tmp/tmp.VzTqmgpZyG
+ touch /tmp/tmp.VzTqmgpZyG/file001 /tmp/tmp.VzTqmgpZyG/file002 ... /tmp/tmp.VzTqmgpZyG/file312
++ find /tmp/tmp.VzTqmgpZyG -type f
++ sort -r
++ head -n1
+ latest_file=/tmp/tmp.VzTqmgpZyG/file312
注意该echo $latest_file
行是不是尽管它出现在 xtrace 中,但还是在这里执行
如果我使用 10,000 个文件,我无法成功运行,所以我怀疑这与头停止寻找早期的。
#!/bin/bash
set -Eeuxo pipefail
test_dir="$(mktemp -d)"
touch "$test_dir/file"{0000..9999}
latest_file="$(find $test_dir -type f | sort -r | head -n1)"
echo $latest_file
如果我抑制错误停止(使用设置 +e),它会成功:
#!/bin/bash
set -Eeuxo pipefail
test_dir="$(mktemp -d)"
touch "$test_dir/file"{0000..9999}
set +e
latest_file="$(find $test_dir -type f | sort -r | head -n1)"
set -e
echo $latest_file
为什么该脚本不能可靠地记录最新文件?
答案1
问题是-e
. Why?-e
使得 bash 在进程以非零退出代码退出时中止(完整规则有点复杂)。如果有管道,则仅计算最后一个命令。
您head -n1
在内部创建了一个错误情况,因为它必须破坏管道(您可以使用来检查它strace
)以忽略其余的输出sort
。
因此,为了使您的脚本可靠地与 一起工作-e
,您可以cat
在管道末尾添加一个。head
仍然会破坏管道,但由于它不再是其中的最后一个命令,因此它不会被考虑在内-e
。cat
对于管道来说是一个无操作:
#!/bin/bash
set -Eeuxo pipefail
test_dir="$(mktemp -d)"
touch "$test_dir/file"{0000..9999}
latest_file="$(find $test_dir -type f | sort -r | head -n1 | cat)"
echo $latest_file
请检查为什么 set -e(或者 set -o errexit,或者 trap ERR)没有达到我预期的效果?了解为什么-e
这是一个不稳定的功能以及它可能带来的问题。最后有很多例子。我最喜欢的:
#!/bin/bash
set -e
foo=$(expr 1 - 1)
echo survived
它会不是打印幸存,该行将不会被执行。但是,如果你有foo=$(expr 2 - 1)
,那么echo
将会被执行!
您最好实施自己的错误检查,-e
这不是最好的解决方案。