`find -exec` 里面这个奇怪的语法是什么? [英] What is this strange syntax inside `find -exec`?

查看:22
本文介绍了`find -exec` 里面这个奇怪的语法是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

最近我遇到了一个奇怪的 bash 脚本,它用于从 find -exec 内部调用自定义 bash 函数.我开发了以下简单的脚本来演示我需要解释的功能.

Recently I've came across a strange bash script, which is used to call a custom bash function from inside find -exec. I've developed following simple script to demonstrate the functionality I need to get explained.

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

In the following example, function foo will be called for each find result.

foo()                                                                                                                                                 
{
    echo "$@"
}
export -f foo

find . -exec bash -c 'foo "$@"' bash {} ;

有人能解释一下 -exec 之后的部分是如何解释的吗?

Can someone explain how the part after -exec is interpreted?

更新:

为了进一步简化这一点,在如上所述导出 foo 之后,为每个 find 结果执行以下操作(假设有一个名为 my_file 的文件).

To further simplify this, after exporting foo as above, following gets executed for each find result (assume there is a file named my_file).

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

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

And this produces the output myfile. I don't understand how this works. What does the second bash does there? Any detailed explanation is appreciated.

(请注意这个问题不是关于find命令的.另外请忽略函数foo的功能,我只是想导出一些函数)

(Please note that this question is not about find command. Also please ignore the functionality of function foo, I just wanted to export some function)

推荐答案

要理解你需要知道4件事:

To understand you need to know 4 things:

  1. find 动作 -exec 允许您对找到的文件和目录应用命令.

  1. The find action -exec allows you to apply a command on the found files and directories.

-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 开始.

  • In bash, $@ expands as all positional parameters ($1, $2...) starting at parameter $1.

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

    In a bash function, the positional parameters are the arguments passed to the function when it is called.

    因此,在您的情况下,为每个找到的文件或目录执行的命令是:

    So, in your case, the command executed for each found file or directory is:

    bash -c 'foo "$@"' bash <the-file>
    

    位置参数因此设置为:

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

    bash 被要求在此上下文中执行 'foo "$@"'."$@" 首先扩展为 "<the-file>".因此,函数 foo 使用一个参数调用:"<the-file>".在函数 foo 的上下文中,位置参数如下:

    and bash is asked to execute 'foo "$@"' in this context. "$@" is first expanded as "<the-file>". So, function foo is called with one single argument: "<the-file>". In the context of function foo the positional parameters are thus:

    $1 = "<the-file>"
    

    echo "$@" 扩展为 echo "<the-file>".

    所有这些只是打印所有找到的文件或目录的名称.就好像你有以下任何一种:

    All this just prints the names of all found files or directories. It is almost as if you had any of:

    find . -exec echo {} ;
    find . -print
    find .
    find
    

    (对于 find 接受最后一个版本的版本).

    (for find versions that accept the last one).

    几乎就像,只是,因为如果文件或目录名称包含空格,取决于你使用 find 和引号,你会得到不同的结果.所以,如果你打算有一个更复杂的 foo 函数,你应该注意引号.例子:

    Almost as if, only, because if file or directory names contain spaces, depending on your use of find and of quotes, you will get different results. So, if you intend to have a more complex foo function, you should pay attention to the quotes. Examples:

    $ 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 命令显然做同样的事情,但是:

    The 3 find commands apparently do the same but:

    $ 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
    

    使用 查找 .-type f -exec bash -c 'bar "$@"' bash {} ;,第一个文件名作为单个参数传递给函数 bar,而在所有其他在这种情况下,它被视为 3 个单独的参数.

    With find . -type f -exec bash -c 'bar "$@"' bash {} ;, the first file name is passed to function bar as one single argument, while in all other cases it is considered as 3 separate arguments.

    这篇关于`find -exec` 里面这个奇怪的语法是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆