让xargs使用别名而不是二进制


14

在CentOS 6.5上的Bash 4.2:

在我中,~/.bash_profile我有一堆别名,包括:

alias grep='grep -n --color=always'

这样我可以在运行时自动获得颜色突出显示和打印行号grep。如果我运行以下命令,则突出显示将按预期工作:

$ grep -Re 'regex_here' *.py

但是,当我最近运行此命令时:

$ find . -name '*.py' | xargs grep -E 'regex_here'

结果没有突出显示,并且没有打印行号,这迫使我返回并显式添加-n --color=alwaysgrep命令中。

  • 难道xargs没有读过环境别名?
  • 如果没有,有没有办法做到这一点?

此问答有您想要的。
psimon 2014年

@psimon对,这实际上是要执行我在解决方法中已经做的事情-我必须在xargs命令中手动扩展别名。我试图找出的是,是否有一种方法可以直接从调用我的别名xargs
MattDMo 2014年

1
export GREP_OPTIONS='-n --color=always'在xargs命令之前尝试过吗?
doneal24

@ DougO'Neal谢谢,成功了!我将其添加到我的中.bash_profile。随时写一个答案...
MattDMo 2014年

Answers:


11

别名在定义它的外壳内部。它对其他进程不可见。Shell函数也是如此。xargs是一个单独的应用程序,它不是外壳程序,因此没有别名或函数的概念。

您可以使xargs调用Shell而不是grep直接调用。但是,仅调用Shell是不够的,您还必须在该Shell中定义别名。如果您在中定义了别名,则.bashrc可以获取该文件。但是,这可能对您.bashrc执行非交互式shell中没有意义的其他任务无效。

find . -name '*.py' | xargs bash -c '. ~/.bashrc; grep -E regex_here "$@"' _

键入正则表达式时,请注意嵌套引用的复杂性。您可以通过将regexp作为参数传递给Shell来简化生活。

find . -name '*.py' | xargs bash -c '. ~/.bashrc; grep -E "$0" "$@"' regex_here

您可以显式执行别名查找。然后xargs会看到grep -n --color=always

find . -name '*.py' | xargs "${BASH_ALIASES[grep]}" regex_here

在zsh中:

find . -name '*.py' | xargs $aliases[grep] regex_here

顺便说一句,请注意,find … | xargs … 其中包含空格的文件名会中断(以及其他)。您可以通过更改为以空分隔的记录来解决此问题:

find . -name '*.py' -print0 | xargs -0 "${BASH_ALIASES[grep]}" regex_here

或使用-exec

find . -name '*.py' -exec "${BASH_ALIASES[grep]}" regex_here {} +

无需调用find,您可以完全在shell内完成所有操作。全局模式以**/递归方式遍历目录。在bash中,您需要先运行shopt -s globstar以启用该glob模式。

grep regex_here **/*.py

这有一些限制:

  • 如果有很多文件匹配(或文件路径较长),则该命令可能会失败,因为它超过了命令行的最大长度。
  • 在bash≤4.2中(但不是在较新的版本中,也不在ksh或zsh中),**/递归到指向目录的符号链接中。

如MariusMatutiae所建议,另一种方法是使用过程替换

grep regex_here <(find . -name '*.py')

**/不适用时,这很有用:对于复杂的find表达式,或者当您不想在符号链接下递归时,在bash≤4.2中使用。请注意,这会破坏包含空格的文件名;一种解决方法是设置IFS和禁用globlob,但是它开始变得有点复杂:

(IFS=$'\n'; set -f; grep regex_here <(find . -name '*.py') )

感谢您对为什么别名对其他进程不可见的清晰解释
MattDMo 2014年

也可以使用流程替换,请参阅我的答案。
MariusMatutiae 2014年

11

采用 alias xargs='xargs '

alias: alias [-p] [name[=value] ... ]
(snip)
A trailing space in VALUE causes the next word to be checked for
alias substitution when the alias is expanded.

谢谢你,我不知道尾随太空把戏。
MattDMo

Np。sudo… 还可以使用…
1.61803 2015年

2

请以此为另一种方法的演示,我在相关的SO问题中找不到 :

您可以编写包装函数,xargs以检查第一个参数是否为别名,如果是,请相应地对其进行扩展。

这是一个完全做到这一点的代码,但是不幸的是,它需要Z shell,因此不能与bash一起运行1:1(坦率地说,我不习惯bash来移植它):

xargs () {
        local expandalias
        if [[ $(which $1) =~ "alias" ]]; then
                expandalias=$(builtin alias $1) 
                expandalias="${${(s.'.)expandalias}[2]}"
        else
                expandalias=$1
        fi
        command xargs ${(z)expandalias} "${(z)@[2,-1]}"
}

证明,它有效:

zsh%alias grep =“ grep -n”´                           #包含匹配的行号
zsh%查找foo -name“ * .p *” | xargs grep -E测试
foo / bar.p0:151:#data = test
foo / bar.p1:122:#data = test#包含行号
zsh%unalias grep 
zsh%查找foo -name“ * .p *” | xargs grep -E测试
foo / bar.p0:#data = test
foo / bar.p1:#data = test#不含行号
zsh% 

1

一个更简单,更优雅的解决方案是使用流程替换

grep -E 'regex_here' <( find . -name '*.py')

它不会像管道那样创建新的外壳,这意味着您仍在定义别名的原始外壳中,并且输出正是您希望的样子。

请注意在重定向和括号之间不留任何空间,否则bash会引发错误。据我所知,Bash,Zsh,Ksh {88,93}支持进程替换,但pdksh却不支持(据说这还不是)。


我认为pdksh开发已死。Mksh或多或少是一个后续项目– “事实证明,这相当艰巨(解析概念在tg @的脑海中完成)”
吉尔斯(Gilles)'所以

进程替换是处理复杂find命令的一种好方法,尽管您需要注意它会在空格处中断,并且不能像find | xargs通过切换到-print0-0或使用那样容易地对其进行修复-exec。适用时,**/更简单,更可靠。
吉尔(Gilles)'所以

0

grep将从环境变量GREP_OPTIONS中读取一组默认选项。如果你把

 export GREP_OPTIONS='--line-number --color=always'

在您的.bashrc中,该变量将传递到子shell,您将获得期望的结果。


但是不要放进--line-number或放进去--color=alwaysGREP_OPTIONS除非只是一个命令,否则会破坏很多脚本。--color=auto可以在那里,仅此而已。将这一行放入您的书中.bashrc会破坏很多东西。
吉尔(Gilles)'所以

@Gilles为根帐户的任何命令设置任何别名或覆盖默认选项是一件坏事。为用户帐户设置这些选项不太可能引起很多问题。我无法提出任何有问题的用户脚本。
doneal24年

几乎所有使用grep的脚本都超出了测试事件是否存在的地步,它将损坏。例如,/etc/init.d/cron在我的系统上:value=`egrep "^${var}=" "$ENV_FILE" | tail -n1 | cut -d= -f2` 。或来自/usr/bin/pdfjampdftitl=`printf "%s" "$PDFinfo" | grep -e … | sed -e …` 。别名不是问题,因为在脚本中看不到别名。
吉尔(Gilles)'所以

@Gilles我知道很多这样的脚本。我无法解决的问题通常仅由root运行(例如/etc/init.d/cron)。就个人而言,我没有在用户帐户上定义任何别名,也没有在rc文件中或通过环境变量设置选项来覆盖命令的默认行为。我更喜欢可预测性而不是方便性。
doneal24

别名不会破坏可预测性,因为脚本看不到它们。设置GREP_OPTIONS会严重破坏可预测性,除了一些选项--color=auto(如其设计目的)之外。
吉尔(Gilles)“所以,别再邪恶了”
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.