次のコマンドを 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
なっていることに注意してください。開き括弧と閉じ括弧でも同じ問題が発生します。ソースでは、セミコロンを2回引用しています。変更\;
;
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'