`find -exec` 中的这个奇怪语法是什么?
What is this strange syntax inside `find -exec`?
最近我遇到了一个奇怪的bash 脚本,它用于从find -exec
内部调用自定义bash 函数。我开发了以下简单脚本来演示我需要解释的功能。
在下面的示例中,将为每个 find
个结果调用函数 foo
。
foo()
{
echo "$@"
}
export -f foo
find . -exec bash -c 'foo "$@"' bash {} \;
有人可以解释一下 -exec
之后的部分是如何解释的吗?
更新:
为了进一步简化,在如上所述导出 foo
之后,对每个 find
结果执行以下操作(假设有一个名为 my_file
的文件)。
bash -c 'foo "$#"' bash my_file
这会产生输出 myfile
。我不明白这是怎么回事。第二个 bash
在那里做什么?任何详细的解释表示赞赏。
(请注意,这个问题不是关于 find
命令的。另外请忽略函数 foo
的功能,我只是想导出一些函数)
要理解你需要知道 4 件事:
find
操作 -exec
允许您对找到的文件和目录应用命令。
-c
bash
选项记录如下:
BASH(1)
...
OPTIONS
...
-c If the -c option is present, then commands are read from
the first non-option argument command_string.
If there are arguments after the command_string, they
are assigned to the positional parameters, starting with [=10=].
...
If bash is started with the -c option, then [=10=] is set to the first
argument after the string to be executed, if one is present.
Otherwise, it is set to the filename used to invoke bash, as given
by argument zero.
在 bash
中,$@
扩展为从参数 [=23= 开始的所有位置参数(</code>、<code>
...) ].
在 bash
函数中,位置参数是调用函数时传递给函数的参数。
因此,在您的情况下,为每个找到的文件或目录执行的命令是:
bash -c 'foo "$@"' bash <the-file>
位置参数因此设置为:
[=12=] = bash
= <the-file>
和 bash
被要求在此上下文中执行 'foo "$@"'
。 "$@"
首先展开为 "<the-file>"
。因此,函数 foo
被调用时带有一个参数:"<the-file>"
。因此,在函数 foo
的上下文中,位置参数为:
= "<the-file>"
和 echo "$@"
扩展为 echo "<the-file>"
。
所有这些只是打印所有找到的文件或目录的名称。这几乎就像你有任何:
find . -exec echo {} \;
find . -print
find .
find
(对于接受最后一个的 find
版本)。
几乎和 一样,只是因为如果文件或目录名称包含空格,根据您对 find
和引号的使用,您会得到不同的结果。所以,如果你打算有一个更复杂的 foo
函数,你应该注意引号。示例:
$ touch "filename with spaces" plain
$ ls -1
filename with spaces
plain # 2 files
$ foo() { echo "$@"; } # print arguments
$ find . -type f
./filename with spaces
./plain
$ find . -type f -exec bash -c 'foo "$@"' bash {} \;
./filename with spaces
./plain
$ find . -type f -exec bash -c 'foo $@' bash {} \;
./filename with spaces
./plain
3 find
命令显然做同样的事情但是:
$ bar() { echo $#; } # print number of arguments
$ wc -w < <(find . -type f)
4 # 4 words
$ find . -type f -exec bash -c 'bar "$@"' bash {} \;
1 # 1 argument
1 # per file
$ find . -type f -exec bash -c 'bar $@' bash {} \;
3 # 3 arguments
1 # 1 argument
对于 find . -type f -exec bash -c 'bar "$@"' bash {} \;
,第一个文件名作为一个参数传递给函数 bar
,而在所有其他情况下,它被视为 3 个单独的参数。
最近我遇到了一个奇怪的bash 脚本,它用于从find -exec
内部调用自定义bash 函数。我开发了以下简单脚本来演示我需要解释的功能。
在下面的示例中,将为每个 find
个结果调用函数 foo
。
foo()
{
echo "$@"
}
export -f foo
find . -exec bash -c 'foo "$@"' bash {} \;
有人可以解释一下 -exec
之后的部分是如何解释的吗?
更新:
为了进一步简化,在如上所述导出 foo
之后,对每个 find
结果执行以下操作(假设有一个名为 my_file
的文件)。
bash -c 'foo "$#"' bash my_file
这会产生输出 myfile
。我不明白这是怎么回事。第二个 bash
在那里做什么?任何详细的解释表示赞赏。
(请注意,这个问题不是关于 find
命令的。另外请忽略函数 foo
的功能,我只是想导出一些函数)
要理解你需要知道 4 件事:
find
操作-exec
允许您对找到的文件和目录应用命令。-c
bash
选项记录如下:BASH(1) ... OPTIONS ... -c If the -c option is present, then commands are read from the first non-option argument command_string. If there are arguments after the command_string, they are assigned to the positional parameters, starting with [=10=]. ... If bash is started with the -c option, then [=10=] is set to the first argument after the string to be executed, if one is present. Otherwise, it is set to the filename used to invoke bash, as given by argument zero.
在
bash
中,$@
扩展为从参数 [=23= 开始的所有位置参数(</code>、<code>
...) ].在
bash
函数中,位置参数是调用函数时传递给函数的参数。
因此,在您的情况下,为每个找到的文件或目录执行的命令是:
bash -c 'foo "$@"' bash <the-file>
位置参数因此设置为:
[=12=] = bash
= <the-file>
和 bash
被要求在此上下文中执行 'foo "$@"'
。 "$@"
首先展开为 "<the-file>"
。因此,函数 foo
被调用时带有一个参数:"<the-file>"
。因此,在函数 foo
的上下文中,位置参数为:
= "<the-file>"
和 echo "$@"
扩展为 echo "<the-file>"
。
所有这些只是打印所有找到的文件或目录的名称。这几乎就像你有任何:
find . -exec echo {} \;
find . -print
find .
find
(对于接受最后一个的 find
版本)。
几乎和 一样,只是因为如果文件或目录名称包含空格,根据您对 find
和引号的使用,您会得到不同的结果。所以,如果你打算有一个更复杂的 foo
函数,你应该注意引号。示例:
$ touch "filename with spaces" plain
$ ls -1
filename with spaces
plain # 2 files
$ foo() { echo "$@"; } # print arguments
$ find . -type f
./filename with spaces
./plain
$ find . -type f -exec bash -c 'foo "$@"' bash {} \;
./filename with spaces
./plain
$ find . -type f -exec bash -c 'foo $@' bash {} \;
./filename with spaces
./plain
3 find
命令显然做同样的事情但是:
$ bar() { echo $#; } # print number of arguments
$ wc -w < <(find . -type f)
4 # 4 words
$ find . -type f -exec bash -c 'bar "$@"' bash {} \;
1 # 1 argument
1 # per file
$ find . -type f -exec bash -c 'bar $@' bash {} \;
3 # 3 arguments
1 # 1 argument
对于 find . -type f -exec bash -c 'bar "$@"' bash {} \;
,第一个文件名作为一个参数传递给函数 bar
,而在所有其他情况下,它被视为 3 个单独的参数。