Mic*_*ael 5 bash wildcards rm parallelism
有时我需要删除目录的所有内容并在那里创建新文件。我可以做这样的事情并期望所有新文件保持完整:
% rm -rf regression/* & ( sleep 10 ; run_regression )
Run Code Online (Sandbox Code Playgroud)
在哪里run_regression为其输出文件添加时间戳,以便它们具有唯一的名称并将它们放入regression?
我的想法是,shell 将解析regression/*为预先存在的文件名的显式列表,然后rm将删除该显式列表中的文件,但不会删除run_regression与rm. 由于run_regression时间戳其文件应该没有名称冲突。
但是,我不太确定如何判断 shell 何时完成列出文件并rm开始工作。以上 10 秒是否足够?我可以做这样的事情bash:
% rm -rf regression/* & ( wait_unil_names_are_resolved ; run_regression )
Run Code Online (Sandbox Code Playgroud)
每条评论澄清我确实在问外壳程序是否保证在调用该工具之前将通配符扩展为文件名,即使它是外壳程序非常熟悉的工具。我可以想象,shell 和工具的开发人员可能会想用工具管道通配符扩展;我希望虽然有标准可以防止这种情况。
尽管您的命令可能有效,但这是一个测试用例:
$ ls
$ echo * $(sleep 1)&touch file1
[1] 12798
$ file1
[1]+ Done echo * $(sleep 1)
Run Code Online (Sandbox Code Playgroud)
注意 file1 没有输入,它是 echo 命令的输出。
编辑:
另一个测试运行:
$ ls
$ touch file1
$ for i in {1..5000}; do rm * & touch file$i; wait;done|grep file
rm: cannot remove '*': No such file or directory
***previous line repeated 14 times***
Run Code Online (Sandbox Code Playgroud)
这不安全。
您尚未指定您要解决的问题是什么。如果您的问题是您希望目录始终存在但不时清理,我建议明确删除早于检查文件的文件(睡眠 1 是我偏执):
touch regression.delete \
&& find regression \! -newer regression.delete -delete & \
&& sleep 1 \
&& run_regression
Run Code Online (Sandbox Code Playgroud)
如果您有子目录,则会出现问题,您可以改为编写
touch regression.delete \
&& find regression -mindepth 1 -maxdepth 1 \! -newer regression.delete -exec rm -rf '{}' \; & \
&& sleep 1 \
&& run_regression
Run Code Online (Sandbox Code Playgroud)
如果您的问题是您想尽快启动程序,如果目录可能暂时不存在并且它不是安装点,我通常会运行类似的命令
mkdir regression.new \
&& chmod --reference regression regression.new \
&& mv regression regression.delete \
&& mv regression.new regression \
&& rm -rf regression.delete & \
run_regression
Run Code Online (Sandbox Code Playgroud)
这应该允许您几乎立即启动 run_regression 。
回复您的编辑(并根据另一个答案的研究编辑我自己),必须在启动命令之前扩展通配符rm,但问题的关键是知道扩展是否在 shell 分叉后完成。据我所知,异步执行的 POSIX 规范没有明确指定一种或另一种方式,第 2.1 节当然暗示扩展是一种不同的操作,并且在命令的实际 fork/exec 之前,但测试(由@adonis,复制由我使用 bash 4.3.42(1)) 表明 bash 采用最有效的方式:如果通配符扩展需要时间,那么通过以下命令执行的修改可以很好地影响该扩展。因此,您最初的想法可能会删除您不想删除的文件。
我查看了 bash 源代码,execute_cmd.c明确指出分叉是在单词扩展之前完成的:
3922 | /* If we're in a pipeline or run in the background, set DOFORK so we
3923 | make the child early, before word expansion. This keeps assignment
3924 | statements from affecting the parent shell's environment when they
3925 | should not. */
Run Code Online (Sandbox Code Playgroud)