要理解你需要知道 4 件事:
The find
action -exec
允许您对找到的文件和目录应用命令。
-
The -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 $0.
...
If bash is started with the -c option, then $0 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.
In bash
, $@
扩展为所有位置参数 ($1
, $2
...) 从参数开始$1
.
In a bash
函数中,位置参数是调用函数时传递给函数的参数。
因此,在您的情况下,为每个找到的文件或目录执行的命令是:
bash -c 'foo "$@"' bash <the-file>
因此,位置参数设置为:
$0 = bash
$1 = <the-file>
and bash
被要求执行'foo "$@"'
在此背景下。"$@"
首先展开为"<the-file>"
。所以,函数foo
用一个参数调用:"<the-file>"
。在功能方面foo
位置参数因此为:
$1 = "<the-file>"
and echo "$@"
展开为echo "<the-file>"
.
所有这些只是打印所有找到的文件或目录的名称。几乎就像您有以下任何一项:
find . -exec echo {} \;
find . -print
find .
find
(for 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
The 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
With find . -type f -exec bash -c 'bar "$@"' bash {} \;
,第一个文件名传递给函数bar
作为一个单独的参数,而在所有其他情况下,它被视为 3 个单独的参数。