我可以在 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
答案1
提示:運行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"
(*
如果當前目錄中有匹配的文件,則需要加引號,並且變數擴展應該用雙引號引起來,除非您知道為什麼需要省略雙引號)。
答案2
跑步巴什命令使用陣列
讓我們試試看:
find /tmp \( -type f -o -type d \) -ls
哇,輸出真多啊…
現在好了:
cmd_list=(find /tmp \()
cmd_list+=(-type f)
cmd_list+=(-o -type d)
cmd_list+=(\) -ls)
"${cmd_list[@]}"
嗯……看起來一模一樣!
find /tmp \( -type f -o -type d \) -ls 2>/dev/null | md5sum
eb49dfe4f05a90797e444db119e0d9bd -
"${cmd_list[@]}" 2>/dev/null| md5sum
eb49dfe4f05a90797e444db119e0d9bd -
好吧,最後:
printf "%q " "${cmd_list[@]}";echo
find /tmp \( -type f -o -type d \) -ls
儘管
printf "%s " "${cmd_list[@]}";echo
find /tmp ( -type f -o -type d ) -ls
我的完整運行版本:
使用數組作為命令的範例
search() {
local OPTIND=0 _o _usage _debug=false
local -a _t _g _cmd=(find)
read -rN9999 _usage <<-EOUsage
Usage: $FUNCNAME [-a] [-d] [-i] [-I] [-H] [-l] [-t type [-t type]] \\
/path/ [path2/ ../path3/] pattern
-t .ext specifying an extension to search for
-d debug, will dump command variable before execution
-[aiIHl] are 'grep' argument, see: man grep.
many type and many path could be given but only one pattern.
EOUsage
while getopts 't:aiIHld' _o ;do
case $_o in
d) _debug=true ;;
t) _t+=(${_t+-o} -name \*.${OPTARG}) ;;
[aiIHl]) _g+=(-$_o) ;;
*) echo "${_usage%$'\n'}" ; return 1 ;;
esac
done
_cmd+=(${@:OPTIND:$#-$OPTIND} -type f)
((${#_t[@]})) && _cmd+=(\( "${_t[@]}" \))
_cmd+=(-exec grep ${_g[@]} ${@:$#} {} +)
$_debug && declare -p _cmd
"${_cmd[@]}"
}
關心<<-EOUsage
從到部分的第一個字符EOUsage
必須做個表格吧!你可以下載這個腳本那裡或作為.txt
:那裡。
筆記:有些grep
參數可以(或必須)賦予search
函數:
search -t txt -Il /tmp/path /home/user 'invoice\|bill'