Bash
如何正確使用 bash 函式的引號?
我正在嘗試在我的
.bashrc
文件中定義以下 bash 函式:function myfind() { find $1 -not -path venv -not -path .tox -name "$2" | xargs grep -n "$3" }
這不是我所期望的。當我使用該功能搜尋文件中的文本時,例如
myfind . *.py test
它不返回任何東西。但是當我直接使用表達式時,即
find . -not -path venv -not -path .tox -name "*.py" | xargs grep -n "test"
它返回一些匹配項。
我已經嘗試使用雙引號,例如
function myfind() { find $1 -not -path venv -not -path .tox -name '"$2"' | xargs grep -n '"$3"' }
或者
function myfind() { find $1 -not -path venv -not -path .tox -name "'$2'" | xargs grep -n "'$3'" }
並試圖逃避像
function myfind() { find $1 -not -path venv -not -path .tox -name \"$2\" | xargs grep -n \"$3\" }
但這些似乎都不起作用。
如何修復這個 bash 函式,以便在參數周圍“使用”引號?
伊蒂姆:
myfind() { find "$1" '(' -name venv -o -name .tox ')' -prune -o \ -name "$2" -type f -exec grep -Hne "$3" -- {} + }
接著:
myfind . '*.py' test
另請參閱為什麼循環查找的輸出是不好的做法?為什麼呼叫類似
xargs
的輸出find
是錯誤的。您的方法的其他一些問題:
-path venv
永遠不會匹配任何東西作為-path
正在考慮的文件的完整路徑上的匹配,這將類似於<contents-of-$1>/subdir/file
. 只有在呼叫的頂層myfind venv ...
才會匹配。我假設您想忽略儲存在名為venv
. 雖然您可以使用! -path '*/venv/*'
它,但首先告訴find
不要進入這些目錄比事後過濾掉其中的所有文件更有效(! -path '*/venv/*'
如果文件路徑在語言環境中不是有效文本,也會有問題) .- 使用
myfind first *.py last
,您要求外殼程序擴展*.py
到目前目錄中的匹配文件列表中,以構成 的倒數第二個參數myfind
,而*.py
您希望將其傳遞給myfind
formyfind
以將其傳遞給find
after的文字參數-name
,因此需要引用該*
字元,以便它不會被 shell 解釋為萬用字元。在這裡,我們用 if or 來引用整個內容*.py
就足夠了,因為其他 3 個字元('*.py'
和)對於shell 來說並不是特殊的。'*'.py``\*.py``.``p``y
如果使用 zsh 而不是 bash,則可以
alias myfind='noglob myfind'
在myfind
. 然後你就可以在myfind . *.py test
不*.py
被外殼擴展的情況下做到這一點。
- 必須引用參數擴展以防止 split+glob (
"$1"
, not$1
)。- 如果沒有
-H
(GNU 擴展)如果find
只找到一個文件,則grep
不會列印其路徑,因此您將不知道匹配項在哪裡。對於grep
不支持的實現,您可以作為額外參數-H
傳遞: ./dev/null``-exec grep -ne "$3" -- /dev/null {} +
- 請參閱
!
與非標準等效的標準(或更短)-not
。- 與
grep -n "$3"
,如果$3
以 開頭-
,它將被 視為一個選項grep
。因此,-e "$3"
相反,其中的內容$3
作為參數傳遞給-e
選項。有同樣的問題find "$1"
,但不幸的是,沒有標準的解決方法。find -- "$1"
會阻止它的內容$1
被視為以開頭的選項,但它仍將被視為謂詞,因此毫無意義。例如,一個名為or的目錄也是一個問題。BSD可以做到這一點,但 GNU和大多數其他實現不支持它。利用find``-``!``(``find``find -f "$1"``find``find``myfind ./-dir-starting-with-data- '*.py' pattern
傳遞以破折號開頭的目錄。- 程式碼中唯一不是標準
sh
語法的是function name()
函式定義語法。ksh 語法是function name {...;}
,Bourne 和標準bash
語法是name() {...;}
. 雖然bash
也是function name() { ...; }
偶然支持,但沒有真正好的理由使用它。- 我已將 a 添加
-type f
到僅考慮的正常文件,因為您可能不想grep
在設備文件或 fifos 中開始搜尋,它會報告目錄或套接字的錯誤。使用 GNUfind
,您可以將其替換為,-xtype f
以便最終解析為正常文件的符號連結也被考慮在內。