在 bash 脚本中对每个文件使用 exec

Using exec on each file in a bash script

我正在尝试为作业编写一个基本的 find 命令(不使用 find)。现在我有一组文件,我想要 exec 一些东西。语法如下所示:

-exec /bin/mv {} ~/.TRASH

我有一个名为 current 的数组,其中包含所有文件。我的数组只包含 /bin/mv{}~/.TRASH(因为我将 -exec 移出)并且位于名为 arguments.[=25= 的数组中]

我需要它,以便每个文件都传递到 {} 并在其上调用 exec。

我想我应该使用 sed 来替换 {} 的内容,像这样(在 for 循环内):

for i in "${current[@]}"; do
    sed "s@$i@{}" 
    #exec stuff?
done

我如何执行其他参数?

你可以这样:

cmd='-exec /bin/mv {} ~/.TRASH'    
current=(test1.txt test2.txt)

for f in "${current[@]}"; do 
   eval $(sed "s/{}/$f/;s/-exec //" <<< "$cmd")
done

使用 eval 命令时要非常小心,因为如果输入来自不受信任的来源,它可能会做一些令人讨厌的事情。


这里尝试避免eval(感谢@gniourf_gniourf的评论):

current=( test1.txt test2.txt )
arguments=( "/bin/mv" "{}" ~/.TRASH )

for f in "${current[@]}"; do
   "${arguments[@]/\{\}/$f}"
done

你很幸运,你的设计还不错,你的参数在一个数组中。

但你肯定不想用eval.

所以,如果我没理解错的话,你有一个文件数组:

current=( [0]='/path/to/file'1 [1]='/path/to/file2' ... )

和一个参数数组:

arguments=( [0]='/bin/mv' [1]='{}' [2]='/home/alex/.TRASH' )

请注意这里没有波浪号,因为 Bash 已经展开了它。

执行你想要的:

for i in "${current[@]}"; do
    ( "${arguments[@]//'{}'/"$i"}" )
done

注意引号。

这将通过 $i 的扩展替换 arguments 字段中出现的所有 {},即文件名 1,并执行这个扩展。请注意,数组的每个字段都将扩展为一个参数(多亏了引号),因此所有这些对于空格、glob 字符等都是非常安全的。这确实是最安全和最正确的处理方式。每个使用 eval 的解决方案都有潜在的危险和破坏(除非使用一些特殊的引号,例如 printf '%q',但这会使该方法无用地尴尬)。顺便说一句,使用 sed 也至少在两个方面被破坏。

请注意,我将扩展包含在子外壳中,因此用户不可能干扰您的脚本。如果没有这个,并且取决于您的完整脚本的编写方式,很容易通过(恶意地)更改一些变量内容或 cd-ing 其他地方来使您的脚本中断。 运行 出于明显的安全原因,您在子 shell 或单独进程中的参数(例如 bash 或 sh 的单独实例——但这会增加额外的开销)确实是强制性的!

请注意,与一些更标准的 find 版本2 相比,使用您的脚本,用户可以直接访问所有 Bash 内置函数(这是一个巨大的优势) !


1 注意 POSIX clearly specifies that this behavior is implementation-defined:

If a utility_name or argument string contains the two characters "{}", but not just the two characters "{}", it is implementation-defined whether find replaces those two characters or uses the string without change.

在我们的例子中,我们选择用文件名替换所有出现的 {}。这与 GNU find 等行为相同。来自 man find:

The string {} is replaced by the current file name being processed everywhere it occurs in the arguments to the command, not just in arguments where it is alone, as in some versions of find.


2 POSIX also specifies that calling builtins is not defined:

If the utility_name names any of the special built-in utilities (see Special Built-In Utilities), the results are undefined.

在你的情况下,它定义得很好!


我认为尝试(在纯 Bash 中)执行 find 命令是一个很棒的练习,应该可以教给您很多东西……尤其是当您获得相关反馈时。我很乐意查看您的代码!