2017-08-10 63 views
0

最近我遇到了一个奇怪的bash脚本,它用于从find -exec内部调用一个自定义bash函数。我开发了以下简单的脚本来演示我需要解释的功能。`find -exec`里面这个奇怪的语法是什么?

在以下示例中,将为每个find结果调用函数foo

foo()                                     
{ 
    echo "[email protected]" 
} 
export -f foo 

find . -exec bash -c 'foo "[email protected]"' bash {} \; 

有人可以解释如何解释-exec之后的部分?


UPDATE:

为了进一步简化此,如上述出口foo后,得到以下用于每个find结果来执行(假定存在一个名为my_file的文件)。

bash -c 'foo "$#"' bash my_file 

并且这产生输出myfile。我不明白这是如何工作的。第二个bash在那里做什么?任何详细的解释赞赏。

(请注意,这个问题是不是find命令也请忽略的功能foo的功能,我只是想出口一些功能)

回答

3

要了解你需要知道的4件事:

  1. find操作-exec允许您在找到的文件和目录上应用命令。

    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. 
    
  2. bash[email protected]膨胀,所有位置参数($1$2 ...)开始参数$1

  3. 如下-cbash选项记录。

  4. bash函数中,位置参数是调用时传递给函数的参数。

所以,你的情况,对于每一个找到的文件或目录执行的命令是:

bash -c 'foo "[email protected]"' bash <the-file> 

的位置参数,因此设置为:

$0 = bash 
$1 = <the-file> 

bash是问在这种情况下执行'foo "[email protected]"'"[email protected]"首先扩展为"<the-file>"。所以,函数foo被调用一个参数:"<the-file>"。在功能foo上下文中的位置参数是这样的:

$1 = "<the-file>" 

echo "[email protected]"和作为膨胀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 "[email protected]"; }        # print arguments 
$ find . -type f 
./filename with spaces 
./plain 
$ find . -type f -exec bash -c 'foo "[email protected]"' bash {} \; 
./filename with spaces 
./plain 
$ find . -type f -exec bash -c 'foo [email protected]' 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 "[email protected]"' bash {} \; 
1             # 1 argument 
1             # per file 
$ find . -type f -exec bash -c 'bar [email protected]' bash {} \; 
3             # 3 arguments 
1             # 1 argument 

随着find . -type f -exec bash -c 'bar "[email protected]"' bash {} \;,第一个文件名被传递给函数bar作为一个单独的参数,而在所有其他情况下,被视为3个独立的论点。

+0

@Leon Ooops,谢谢。固定。 –

+0

BTW,我收回我给予好评,因为海事组织,(更新)回答的第二部分没有解决OP的问题,因此可能有些误导 – Leon

+0

@Leon没问题。我明白你的观点。我添加了第二部分,因为我怀疑真正的'foo'函数比OP显示的要复杂得多(否则,这将是无用的)。如果我没有错,它确实会有所作为......我试图让它更清晰一些。 –

相关问题