我的.bashrc无法实现别名/替换功能

时间:2019-06-06 13:15:58

标签: linux bash shell unix command-line

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

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

但是使用此代码会发生意外行为。它删除了我的报价。

GNU bash,版本4.4.23(1)-发行版(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

因此第二个变体没有使用我的引号,也没有按预期运行。

2 个答案:

答案 0 :(得分:2)

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

当我将函数(*)定义为

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命令之间的区别在于,您的函数将使用隐式-exec(AND)运算符附加一个-a操作。如果没有明确的操作,find将打印所有匹配的结果。

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

您可以比较这三个命令的输出

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' \)

避免出现问题。


(*)此函数定义是从问题中复制的。
除非对Korn Shell样式find() { ... }有特殊要求,否则应改用便携式POSIX样式function find { ... }

答案 1 :(得分:1)

按照书面规定,-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