最近我遇到了一个奇怪的bash脚本,用于从find -exec
内部调用自定义bash函数。我开发了以下简单的脚本来演示我需要解释的功能。
在以下示例中,将为每个foo
结果调用函数find
。
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
的功能,我只想导出一些函数)
答案 0 :(得分:3)
要了解你需要知道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 $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.
在bash
中,$@
展开所有位置参数($1
,$2
...),从参数$1
开始。
在bash
函数中,位置参数是调用函数时传递给函数的参数。
因此,在您的情况下,为每个找到的文件或目录执行的命令是:
bash -c 'foo "$@"' bash <the-file>
因此,位置参数设置为:
$0 = bash
$1 = <the-file>
要求和bash
在此上下文中执行'foo "$@"'
。 "$@"
首先展开为"<the-file>"
。因此,使用一个参数调用函数foo
:"<the-file>"
。在函数foo
的上下文中,位置参数因此是:
$1 = "<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个单独的参数。