Bash

find 命令在函式內部時拋出錯誤

  • April 7, 2019

我可以在 bash 中執行以下命令而不會出現任何錯誤:

$ find /d/Code/Web/Development/Source/ \( -name '*.cs' -o -name '*.cshtml' \) -exec grep -IH UserProfileModel {} \;

我在 .bash_aliases 中寫了一個函式來快速執行這個命令:

search() {
   local file_type file_types find_cmd opt OPTARG OPTIND or pattern usage
   
   usage="Usage: search [OPTION] ... PATTERN [FILE] ...
Search for PATTERN in each FILE.
Example: search -t c -t h 'hello world' /code/internal/dev/ /code/public/dev/

Output control:
 -t    limit results to files of type"
   
   if [[ $1 == --help ]]; then
       echo "$usage"
       return
   fi
   
   file_types=()
   while getopts ":t:" opt; do
       case $opt in
           t)
               file_types+=("$OPTARG")
               ;;
           ?)
               echo "$usage"
               return
               ;;
       esac
   done
   shift $((OPTIND-1))
   
   if (( $# == 0 )); then
       echo "$usage"
       return
   fi
   
   pattern=$1
   shift
   
   if (( $# == 0 )); then
       echo "$usage"
       return
   fi
   
   find_cmd=(find "$@" '\(')
   or=""
   for file_type in "${file_types[@]}"; do
       find_cmd+=($or -name \'*.$file_type\')
       or="-o"
   done
   find_cmd+=('\)' -exec grep -IH "$pattern" {} '\;')
   
   "${find_cmd[@]}"
}

但是,該函式會引發錯誤:

find: paths must precede expression

如果我將最後一行更改為echo "${find_cmd[@]}",它將列印與上面完全相同的命令:

$ search -t cs -t cshtml UserProfileModel /d/Code/Web/Development/Source/
find /d/Code/Web/Development/Source/ \( -name '*.cs' -o -name '*.cshtml' \) -exec grep -IH UserProfileModel {} \;

我不明白為什麼它在控制台中執行時會起作用,但在函式中執行時會失敗。

另外,如果我將功能簡化為它可以工作的命令:

search() {
   find /d/Code/Web/Development/Source/ \( -name '*.cs' -o -name '*.cshtml' \) -exec grep -IH UserProfileModel {} \;
}

我在 Notepad++ 中編輯 .bash_aliases,但我確保行尾是 Unix 格式。

編輯

根據 F. Hauri 下面的建議,我啟用了調試。顯然這是實際正在執行的命令:

find /d/Code/Web/Development/Source/ '\(' -name ''\''*.cs'\''' -o -name ''\''*.cshtml'\''' '\)' -exec grep -IH UserProfileModel '{}' '\;'

我不確定如何處理這些資訊。在括號之前刪除轉義字元會導致它引發不同的錯誤:

find: missing argument to -exec

提示:執行set -x以啟用跟踪模式。Bash 在執行之前列印每個命令。執行set +x以關閉跟踪模式。

+ find . '\(' '\)' -exec grep -IH needle '{}' '\;'

注意最後一個參數find是如何\;代替;. 左括號和右括號也有同樣的問題。在您的來源中,您已經引用了兩次分號。改變

   find_cmd=(find "$@" '\(')
   …
   find_cmd+=('\)' -exec grep -IH "$pattern" {} '\;')

   find_cmd=(find "$@" '(')
   …
   find_cmd+=(')' -exec grep -IH "$pattern" {} ';')

或者

   find_cmd=(find "$@" \()
   …
   find_cmd+=(\) -exec grep -IH "$pattern" {} \;)

此外,-name \'*.$file_type\'有錯誤的引號 - 您正在尋找名稱以單引號開頭和結尾的文件。做這個-name "*.$file_type"*如果目前目錄中有匹配的文件,則需要引用,並且變數擴展應該用雙引號引起來,除非您知道為什麼需要省略雙引號)。

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