【问题标题】:Can't realize alias/substitution function for my .bashrc [duplicate]无法为我的 .bashrc 实现别名/替换功能 [重复]
【发布时间】:2019-06-06 13:15:58
【问题描述】:

我正在尝试为我的 find 命令着色,因此我已将此别名函数添加到我的 .bashrc 中。

# liberate your find
function find
{
    command find $@ -exec ls --color=auto -d {} \;
}

但是使用此代码会出现意外行为。它放弃了我的报价。

GNU bash,版本 4.4.23(1)-release (x86_64-pc-linux-gnu)

使用我的功能:

find ./ -name '*.pl' -or -name '*.pm'

结果:

./lib/cover.pm
./lib/db.pm

使用相同的查找功能但内置:

command find ./ -name '*.pl' -or -name '*.pm'

结果:

./auth.pl
./index.pl
./title.pl
./lib/cover.pm
./lib/db.pm
./fs2db.pl

所以第二个变体并没有吃掉我的报价,而是按其应有的方式工作。

【问题讨论】:

    标签: linux bash shell unix command-line


    【解决方案1】:

    为了重现问题,我创建了所有文件,如问题中较长的结果中所示。

    当我将函数(*)定义为

    function find
    {
        command find $@ -exec ls --color=auto -d {} \;
    }
    

    并执行

    find ./ -name '*.pl' -or -name '*.pm'
    

    我收到一条错误消息

    find: paths must precede expression: fs2db.pl
    Usage: find [-H] [-L] [-P] [-Olevel] [-D help|tree|search|stat|rates|opt|exec] [path...] [expression]
    

    因为*.pl 被shell 扩展为auth.pl fs2db.pl index.pl title.pl

    我不得不将函数更改为

    function find
    {
        command find "$@" -exec ls --color=auto -d {} \;
    }
    

    重现您的问题。 (也许这取决于外壳。我用 bash 4.4.19(3)-release 进行了测试)

    set -x 之后,你可以看到 shell 在执行你的函数时做了什么:

    $ find ./ -name '*.pl' -or -name '*.pm'
    + find ./ -name '*.pl' -or -name '*.pm'
    + command find ./ -name '*.pl' -or -name '*.pm' -exec ls --color=auto -d '{}' ';'
    + find ./ -name '*.pl' -or -name '*.pm' -exec ls --color=auto -d '{}' ';'
    ./lib/cover.pm
    ./lib/db.pm
    

    执行您的函数和直接执行find 命令之间的区别在于,您的函数附加了一个带有隐式-a (AND) 运算符的-exec 操作。如果没有明确的操作,find 会打印所有匹配的结果。

    您会看到运算符优先级 -a (AND) 高于 -o (=-or, OR) 的结果

    你可以比较这3个命令的输出

    command find ./ -name '*.pl' -or -name '*.pm'
    command find ./ -name '*.pl' -or -name '*.pm' -print
    command find ./ \( -name '*.pl' -or -name '*.pm' \) -print
    

    http://man7.org/linux/man-pages/man1/find.1.html#NON-BUGS

    你可以把你的函数称为

    find ./ \( -name '*.pl' -or -name '*.pm' \)
    

    为了避免这个问题。


    (*) 这个函数定义是从问题中复制而来的。
    您应该改用可移植的 POSIX 样式 find() { ... },除非对 Korn shell 样式 function find { ... } 有特定要求。

    【讨论】:

    • 谢谢。它解释了问题。
    • 顺便说一句,function find { 是传统的 ksh 语法;请考虑使用现代(POSIX 兼容)find() {;有关详细信息,请参阅wiki.bash-hackers.org/scripting/obsolete
    【解决方案2】:

    正如所写,-exec 主要仅适用于 -or 运算符右侧的代码。您需要为您的参数加上括号,以便-exec 适用于匹配的所有内容。您还需要从其他参数中提取路径(如果您想指定多个路径,这会变得混乱,因为您的函数必须决定将括号放在哪里;区分路径和其他表达式将相当于重新实现一大块find 的解析。我假设你在这里只传递一个路径)。

    find ()
    {
        path=$1
        shift
        command find "$path" \( "$@" \) -exec ls --color=auto -d {} \;
    }
    

    或者,您可以将括号放在命令行中,而不更改当前定义。

    find ./ \( -name '*.pl' -or -name '*.pm' \)
    

    你原来的函数运行

    find ./ -name '*.pl' -or -name '*.pm' -exec ls --color=auto -d {} \;
    

    相当于

    find ./ -name '*.pl' -or \( -name '*.pm' -exec ls --color=auto -d {} \; \)
    

    没有隐含的-print

    【讨论】:

    • 没有解决问题。 find: paths must precede expression: `./' find: possible unquoted pattern after predicate `('?
    • 如何去掉\( "$@" \)引号外的路径参数?
    • 啊,我错过了路径是函数的参数之一。这有点棘手。
    • 谢谢。问题已经解决了。抱歉,我还不能投票。
    猜你喜欢
    • 2019-02-02
    • 1970-01-01
    • 2020-03-03
    • 2020-06-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-31
    • 1970-01-01
    相关资源
    最近更新 更多