procura conteúdo de arquivos que são compactados em um arquivo zip

2

Para o meu projeto de escola eu tenho que criar um script que permite que você pesquise o conteúdo dos arquivos que são embalados em um arquivo zip. Você pode fornecer uma "string de pesquisa" com o script, seguido por um ou mais arquivos zip, da seguinte maneira:

./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

Eu tentei, mas eu não sei como dar um segundo parâmetro, alguém pode me ajudar por favor? Obrigado! aqui está o meu código:

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/
    
por carlos 28.05.2016 / 15:32

2 respostas

3

Isso faz o que você quer, e também é deliberadamente mais capaz do que estritamente precisa ser.

Como você disse que era estudante, eu queria não apenas responder à sua pergunta, mas também criar um exemplo bastante simples de como usar getopts para processar opções e argumentos da linha de comando ... e também como um pouco mais trabalho com opções pode estender a funcionalidade básica para adicionar alguns recursos úteis.

As opções -e , -v , -i , -H e -h são as mesmas usadas em grep e algumas outras ferramentas comuns, para que os usuários se beneficiem do conhecimento existente e não utilizem não precisa aprender opções novas e incompatíveis.

Para acelerar várias pesquisas dos mesmos arquivos .zip, o script também armazena em cache a saída de unzip -v para cada arquivo (em /var/tmp/ por padrão). Opções de linha de comando -c e -C podem ser usadas para limpar os arquivos de cache antes ou depois (ou ambos) da pesquisa.

Finalmente, usei aspas duplas em torno do uso ALL das variáveis exceto nos casos específicos em que as aspas duplas podem causar problemas - por exemplo, quando eles possuem argumentos opcionais para o comando grep - sem aspas, eles não adicionam nada aos argumentos que serão passados para grep , mas se fossem citados com aspas duplas, eles adicionariam a sequência vazia a esses argumentos. Este é um exemplo de um dos poucos casos em que você não deve citar duas vezes suas variáveis. Em todos os outros casos, use aspas duplas.

Nota: como apontado pelo G-Man, a única razão pela qual é razoavelmente seguro usar $IGNORECASE sem aspas é porque eu o configurei explicitamente para um valor conhecido e seguro (isto é, sem espaços ou asteriscos ou outros caracteres problemáticos) antes que eu usei, então eu sei para o fato de que não pode conter qualquer outro valor. Esse certo conhecimento me permitiu preguiça de citar neste caso em particular.

No entanto, seria mais seguro usar ${IGNORECASE:+"$IGNORECASE"} , especialmente se ele pudesse conter um valor arbitrário desconhecido (por exemplo, atribuído a partir da linha de comando em vez de codificado no script).

BTW, ${varname:+"$varname"} retorna absolutamente nada (nem mesmo a string vazia) se $varname estiver vazio OU o valor com aspas duplas de $varname se não estiver vazio.

Use o script assim:

$ ./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

ou:

$ ./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

ou:

$ ./searchzip.sh -i -e Tom file*.zip | awk -F: '{print $1}' | sort -u
file1.zip
file2.zip
file3.zip
file4.zip

De qualquer forma, aqui está o script:

#!/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

A estrutura básica do programa é:

  1. defina uma função usage() para imprimir uma mensagem de ajuda (com mensagem de erro opcional)

  2. defina padrões para algumas variáveis

  3. processe as opções da linha de comando

  4. execute qualquer verificação de integridade e pós-processamento necessária para essas opções e seus argumentos

  5. Finalmente, o loop principal do programa que faz todo o trabalho.

Esta é uma estrutura muito comum e muito simples que você pode usar em muitos programas.

BTW, eu não coloquei nenhum comentário no loop principal. Eu senti que eles seriam redundantes, pois usei nomes de variáveis significativos, de modo que os comentários seriam apenas paráfrases triviais do código, como "# do foo" antes de fazer "foo". Se e quando necessário, eu teria feito comentários sempre que eu sentisse que o código não era auto-explicativo.

    
por 29.05.2016 / 06:32
1

aqui é uma solução primitiva:

#!/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

Por favor, sinta-se à vontade para me perguntar sobre isso com comentários para que eu possa melhorá-lo.

    
por 29.05.2016 / 09:20