Bash

如何正確使用 bash 函式的引號?

  • May 18, 2022

我正在嘗試在我的.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您希望將其傳遞給myfindformyfind以將其傳遞給findafter的文字參數-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 中開始搜尋,它會報告目錄或套接字的錯誤。使用 GNU find,您可以將其替換為,-xtype f以便最終解析為正常文件的符號連結也被考慮在內。

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