对于我的学校项目,我必须创建一个脚本,允许您搜索 zip 文件中打包的文件的内容。您可以在脚本中指定一个“搜索字符串”,后跟一个或多个 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
我尝试了,但我不知道如何给出第二个参数,有人可以帮助我吗?谢谢你!这是我的代码:
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
,但如果它们是双引号的,它们将添加空字符串到这些参数。这是极少数情况之一的示例,您可以不应该双引号你的变量。在所有其他情况下,请使用双引号。
注:正如 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
请随时通过评论向我询问,以便我可以改进它。