よく使うコマンドを置き換えるためにbashスクリプトを作成しようとしています。私のファイルのコードです。test.sh
#!/bin/bash
echo -e "\n"
i=0
args[i++]=$0
for arg in $@ ; do
args[i++]=$arg
done
where="."
what="-type f"
gcase=
str=
while getopts "d:f:F:ih" opt ; do
case $opt in
h)
echo -e "This is the help of this search function."
echo -e "\t $0 [-d <dir>] [-f|-F <pattern>] [-i] string"
echo -e "This will output the result of"
echo -e "\t find dir -[i]name pattern -exec grep --color -Hn[i] string {} \;"
echo -e "Default is"
echo -e "\t find . -type f -exec grep --color -Hn string {} \;\n"
exit 0
;;
d)
OPTIND=$(($OPTIND-1))
where=
tmp=${args[$OPTIND]}
while [[ $OPTIND -lt $# ]] && [[ "${tmp:0:1}" != "-" ]] ; do
where="$where"" $tmp"
OPTIND=$(($OPTIND+1))
tmp=${args[$OPTIND]}
done
;;
F)
what="-iname "
what="$what""\"$OPTARG\""
;;
f)
what="-name "
what="$what""\"$OPTARG\""
;;
i)
gcase="-i"
;;
\?)
echo "Invalide option, use option -h for help." >&2
exit 0
;;
esac
done
str=${args[$OPTIND]}
command="find $where $what -exec grep --color -Hn $gcase \"$str\" {} \;"
echo "$command"
$command
これで端末でこれを行うと、次./test.sh -d auto-avoid -F "TEST*" "main"
のような結果が得られます。
find auto-avoid -iname "TEST*" -exec grep --color -Hn "main" {} \;
find: missing argument to `-exec'
(auto-avoid
私が楽しんで書いた小さなC ++プログラムを含むディレクトリです。)
その後、端末にコマンドをコピーして貼り付けると、次のような結果がfind auto-avoid -iname "TEST*" -exec grep --color -Hn "main" {} \;
表示されます。
auto-avoid/test.cpp:26:int main(int argc, char **argv)
これは予想される結果です。
問題は私が何を逃していますか?
私は今テストするためにスタンドアロンスクリプトで書いていますが、目標はこれを私のものです.bash_aliases
。
同様のトピックを見つけましたが、何も役に立ちませんでした。この質問が重複した質問であると思われる場合は、喜んで回答いたします。
何人かの人々は私に使用するように言うと確信していますgrep -r
。しかし、少なくとも私のスクリプトがうまくいかない理由を理解したいと思います。これは最小限の「動作しない」例です。後でいくつかのディレクトリを除外しますfind
。
答え1
使用set -x
シェルが実際に実行しようとしていることを確認してください。
$ command='find foo -iname "TEST*" -exec grep --color -F -Hn "main" {} \;'
$ echo "$command"
find foo -iname TEST* -exec grep --color -F -Hn main {} \;
$ set -x
$ $command
+ find foo -iname 'TEST*' -exec grep --color -F -Hn main '{}' '\;'
find: missing argument to `-exec'
注'\;'
:文字通りバックスラッシュを提供していますが、find
これは予想されたものとは異なります。
二重引用符はバックスラッシュと同じ機能を実行し、セミコロンをエスケープしてコマンド区切り文字ではなく文字として扱います。
以下は同じでなければなりません。
$ foo="something ;"
$ foo=something\ \;
また、コマンドラインを実行する$command
のは少し面倒です。生成されたコマンドの引数(pathnameなど)にスペースがある場合は分割さ$where
れます。シェル配列これを行うより強力な方法を提供します。