讓 xargs 使用別名而不是二進制
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=always
到grep
命令中。
- 不
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.