学校プロジェクトでは、zipファイルで圧縮されたファイルの内容を取得できるスクリプトを作成する必要があります。次のように、スクリプトに「検索文字列」と1つ以上のzipファイルを指定できます。
./searchZip.sh -s Tom ztest1.zip ztest2.zip
Found the word 'Tom' in the following files:
ztest1.zip : script1_q0638730_04-18-23-04-41.txt
ztest2.zip : script2_q0638730-04-25-19-52-07.txt
私は試しましたが、2番目のパラメータをどのように提供するのかわかりません。誰でも助けることができますか?ありがとうございます!これは私のコードです。
function unzipFile()
{
unzip ztest1.zip -d zipFiles
unzip ztest2.zip -d zipFiles
unzip ztest3.zip -d zipFiles
}
if test -z "$1"
then
echo "Enter a name please "
exit
else
unzipFile
echo "Found the word '$1' in the following files:"
grep -ilR "$1" zipFiles/
fi
rm -r zipFiles/
答え1
これはあなたのニーズに合わせて機能し、必要なものよりも意図的に強力です。
あなたが学生だと言ったので、私はあなたの質問に答えるだけでなく、getopts
...を使用してコマンドラインオプションと引数を処理する方法とオプションを使用してより多くのタスクを実行する方法の非常に簡単な例を作成します。したかった。基本機能にいくつかの便利な機能を追加するように拡張されました。
-e
、、、およびオプションは、一般的に使用されている他のツールで使用されているオプションと同じであるため、-v
ユーザーは互換性のない新しいオプションを学ぶことなく既存の知識を利用できます。-i
-H
-h
grep
同じ.zipファイルの複数の検索を高速化するために、スクリプトはunzip -v
各ファイルの出力もキャッシュします(/var/tmp/
デフォルトでは)。コマンドラインオプションを使用して、検索前または検索後(またはその両方)のキャッシュファイルを消去-c
できます。-C
最後に二重引用符を使用しました。みんな変数の使用とは別に二重引用符が問題を引き起こす可能性がある特定の場合、つまりコマンドのオプション引数を保持するgrep
ときに引用符が付けられていない場合は、渡される引数には何も追加しませんが、二重引用符で囲まれているgrep
場合は空の文字列を追加します。パラメータ。これはあなたができる非常に少数の状況の1つの例です。してはいけない変数を二重引用符で囲みます。他のすべての場合は二重引用符を使用してください。
注:G-Manが指摘したように、ただこのように引用符なしで使用するのがかなり安全な理由$IGNORECASE
は、使用する前にそれを既知の安全な値に明示的に設定するためです(たとえば、スペース、アスタリスク、またはその他の問題のある文字はありません)。知る実際には異なる価値を持つことはできません。この特定の知識のために、この特定のケースについては引用できません。
${IGNORECASE:+"$IGNORECASE"}
ただし、特に不明な任意の値(スクリプトにハードコードされていないコマンドラインから割り当てられた値など)が含まれている可能性がある場合は、使用する方が安全です。
ところで、空の場合は${varname:+"$varname"}
何も返されません(空の文字列も同じです)。$varname
または$varname
空でない場合は、二重引用符で囲まれた値です。
次のスクリプトを使用します。
$ ./searchzip.sh -h -e Tom file*.zip
113 Defl:N 64 43% 2016-05-29 15:45 cf747915 a/Tom.txt
113 Defl:N 64 43% 2016-05-29 15:45 cf747915 tomato/Tom.txt
または:
$ ./searchzip.sh -i -e Tom file*.zip
file1.zip: 113 Defl:N 64 43% 2016-05-29 15:45 cf747915 a/Tom.txt
file2.zip: 113 Defl:N 64 43% 2016-05-29 15:45 cf747915 b/tom.txt
file3.zip: 113 Defl:N 64 43% 2016-05-29 15:45 cf747915 c/tom3.txt
file4.zip: 0 Stored 0 0% 2016-05-29 15:50 00000000 tomato/
file4.zip: 113 Defl:N 64 43% 2016-05-29 15:45 cf747915 tomato/Tom.txt
または:
$ ./searchzip.sh -i -e Tom file*.zip | awk -F: '{print $1}' | sort -u
file1.zip
file2.zip
file3.zip
file4.zip
とにかくスクリプトは次のようになります。
#!/bin/bash
#set -x
# 1. define usage() function to print help
usage() {
[ -n "$*" ] && echo "$@" $'\n' > /dev/stderr
cat > /dev/stderr <<__EOF__
Usage: $0 [-HhicC] [-d cachedir ] [-e PATTERN] [ -v PATTERN ] zipfile...
-e Pattern to search for
-v Pattern to exclude from search
-i Ignore case when searching
-H Include .zip filenames in output (default)
-h Suppress .zip filenames in output
-d Directory to use for temporary listing files (default /var/tmp)
-c Delete cache files before searching
-C Delete cache files after searching
-h This help message
Either -e or -v may be specified multiple times
__EOF__
exit 1;
}
# 2. set some defaults
CLEANUP=0
CLEAR=0
IGNORECASE=''
FNAMES='-H'
EXCL=''
pattern=''
exclude=''
cache_dir="/var/tmp"
# 3. process command-line options
while getopts ":s:e:v:d:CchHi" opt; do
case "$opt" in
s|e) pattern+="$OPTARG|" ;; # -s is an undocumented alias for -e
v) exclude+="$OPTARG|" ;;
d) cache_dir="$OPTARG" ;;
C) CLEANUP='1' ;;
c) CLEAR='1' ;;
h) FNAMES='-h' ;;
H) FNAMES='-H' ;;
i) IGNORECASE='-i' ;;
*) usage ;;
esac
done
shift $((OPTIND-1))
# 4. check and post-process options and their args
[ -z "$pattern" ] && usage 'ERROR: -e option is required'
# remove trailing '|' from $pattern and $exclude
pattern="${pattern%|}"
exclude="${exclude%|}"
# 5. the main loop of the program that does all the work
for f in "$@" ; do
if [ -e "$f" ] ; then
cache_file="$cache_dir/$f.list"
search_file="$cache_file.search"
[ "$CLEAR" -eq 1 ] && rm -f "$cache_file"
if [ ! -e "$cache_file" ] ; then
unzip -v "$f" > "$cache_file"
fi
grep "$FNAMES" $IGNORECASE -E "$pattern" "$cache_file" > "$search_file"
# safer to use ${IGNORECASE:+"$IGNORECASE"}
if [ -z "$exclude" ] ; then
sed -e "s/^.*$f[^:]*:/$f:/" "$search_file"
else
sed -e "s/^.*$f[^:]*:/$f:/" "$search_file" |
grep $IGNORECASE -v -E "$exclude"
# or use ${IGNORECASE:+"$IGNORECASE"}
fi
rm -f "$search_file"
[ "$CLEANUP" -eq 1 ] && rm -f "$cache_file"
fi
done
プログラムの基本構造は次のとおりです。
usage()
ヘルプメッセージを出力する関数の定義(オプションのエラーメッセージを含む)一部の変数のデフォルト値の定義
コマンドラインオプションの処理
これらのオプションとその引数に必要な完全性チェックと後処理を実行します。
最後に、メインプログラムループがすべてのタスクを完了します。
これは、多くのプログラムで使用できる非常に一般的で非常に単純な構造です。
しかし、私はメインループにコメントを追加しませんでした。意味のある変数名を使用しているので重複しているようで、コメントは「foo」を実行する前の「#do foo」のようなコードのマイナーな説明にすぎません。必要に応じて、コードが説明が必要だと思われる部分について説明します。
答え2
元の解決策は次のとおりです。
#!/bin/bash
if [[ "$#" -le 0 ]]; then
echo "Usage : ./searchZip.sh -s Tom ztest1.zip ztest2.zip"
exit 0
fi
case $1 in
-s) str="$2"
shift 2
for i in "$@"; do
echo "searching for $str in $i ... "
if ( unzip -c "$i" | grep "$str" 1>/dev/null ); then
unzip "$i" -d ./tmp > /dev/null
grep -rl "$str" ./tmp
rm -r ./tmp
fi
done;;
*) echo "Usage ... "
;;
esac
改善できるようにコメントでお気軽にお問い合わせください。