Bash

讓 xargs 使用別名而不是二進制

  • November 21, 2015

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讀取環境中的別名?
  • 如果沒有,有沒有辦法讓它做到這一點?

別名在定義它的 shell 內部。它對其他程序不可見。shell 函式也是如此。xargs是一個單獨的應用程序,它不是外殼,因此沒有別名或函式的概念。

您可以讓 xargs 呼叫 shell 而不是grep直接呼叫。然而僅僅呼叫一個 shell 是不夠的,你還必須在那個 shell 中定義別名。如果別名在您的 中定義.bashrc,您可以獲取該文件;但是,這可能無法讓您.bashrc執行在非互動式 shell 中沒有意義的其他任務。

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

輸入正則表達式時,請注意嵌套引用的複雜性。您可以通過將正則表達式作為參數傳遞給 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 內完成所有操作,而不是呼叫。glob 模式**/遞歸地遍歷目錄。在 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和禁用 globbing,但它開始變得有點複雜:

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

採用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.

引用自:https://unix.stackexchange.com/questions/141367