zip 파일로 압축된 파일의 내용을 검색합니다.

zip 파일로 압축된 파일의 내용을 검색합니다.

학교 프로젝트의 경우 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

프로그램의 기본 구조는 다음과 같습니다.

  1. usage()도움말 메시지를 인쇄하는 함수 정의 (선택적 오류 메시지 포함)

  2. 일부 변수에 대한 기본값 정의

  3. 명령줄 옵션 처리

  4. 이러한 옵션과 해당 인수에 대해 필요한 온전성 검사 및 사후 처리를 수행합니다.

  5. 마지막으로 메인 프로그램 루프가 모든 작업을 완료합니다.

이는 많은 프로그램에서 사용할 수 있는 매우 일반적이고 매우 간단한 구조입니다.

그런데 저는 메인 루프에 어떤 코멘트도 추가하지 않았습니다. 의미 있는 변수 이름을 사용하고 있기 때문에 중복되는 것 같아서 주석은 "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

개선할 수 있도록 댓글을 통해 언제든지 문의해 주세요.

관련 정보