Come posso ricorrere in modo ricorsivo agli archivi compressi?


16

Sto cercando di scoprire quali moduli use Test::Versionin cpan. Quindi ho usato minicpanper rispecchiarlo. Il mio problema è che ho bisogno di scorrere gli archivi scaricati e di eseguire il grep dei file che si trovano negli archivi. Qualcuno può dirmi come potrei farlo? preferibilmente in un modo che mi dice quale file nell'archivio e su quale linea è su.

(nota: non sono tutti tarball alcuni sono file zip)

Risposte:


18

Ok, applichiamo la filosofia unix. Quali sono i componenti di questa attività?

  • Ricerca di testo: è necessario uno strumento per cercare testo in un file, ad esempio grep.
  • Ricorsivo: è necessario uno strumento per cercare file in un albero di directory, ad esempio find.
  • Archivi: è necessario uno strumento per leggerli.

La maggior parte dei programmi unix funziona su file. Quindi per operare facilmente sui componenti di archivio, è necessario accedervi come file, in altre parole è necessario accedervi come directory.

Il filesystem AVFS presenta una vista del filesystem in cui ogni file di archivio /path/to/foo.zipè accessibile come directory ~/.avfs/path/to/foo/zip#. AVFS fornisce l'accesso in sola lettura ai formati di file di archivio più comuni.

mountavfs
find ~/.avfs"$PWD" \( -name '*.zip' -o -name '*.tar.gz' -o -name '*.tgz' \) \
     -exec sh -c '
                  find "$0#" -name "*.pm" -exec grep "$1" {\} +
                 ' {} 'Test::Version' \;
fusermount -u ~/.avfs   # optional

spiegazioni:

  • Montare il filesystem AVFS.
  • Cerca i file di archivio in ~/.avfs$PWD, che è la vista AVFS della directory corrente.
  • Per ogni archivio, eseguire lo snippet di shell specificato (con $0= nome archivio e $1= modello da cercare).
  • $0#è la vista della directory dell'archivio $0.
  • {\}piuttosto che {}è necessario nel caso delle esterne findsostituti {}all'interno -exec ;argomenti (alcuni lo fanno, altri no).
  • Opzionale: smonta finalmente il filesystem AVFS.

O in zsh ≥4.3:

mountavfs
grep 'Test::Version' ~/.avfs$PWD/**/*.(tgz|tar.gz|zip)(e\''
     reply=($REPLY\#/**/*.pm(.N))
'\')

spiegazioni:

  • ~/.avfs$PWD/**/*.(tgz|tar.gz|zip) corrisponde agli archivi nella vista AVFS della directory corrente e delle sue sottodirectory.
  • PATTERN(e\''CODE'\')applica CODICE a ciascuna partita di PATTERN. Il nome del file corrispondente è in $REPLY. L'impostazione replydell'array trasforma la corrispondenza in un elenco di nomi.
  • $REPLY\# è la vista della directory dell'archivio.
  • $REPLY\#/**/*.pmcorrisponde ai .pmfile nell'archivio.
  • Il Nqualificatore glob fa espandere il modello in un elenco vuoto se non c'è corrispondenza.

questo crea l'altro problema dell'intestino di dover montare e poi smontare tutti gli archivi, poiché parte del problema è che ci sono 22k archivi che devono essere cercati
xenoterracide,

@xenoterracide: come è un problema? Con AVFS, hai un singolo mount point ( ~/.avfs) e l'accesso a ciascun archivio è automatico ( ~/.avfs/path/to/archive.zip\#è una normale directory sul filesystem AVFS, non un mount point). Certo, ogni archivio a cui accedi significa un piccolo calo delle prestazioni, ma questo è intrinseco al problema.
Gilles 'SO- smetti di essere malvagio'

@gilles solo il fatto che ora devo passare attraverso e capire come montarli prima, il che sembra un po 'una cattiva idea, meglio montarli mentre vado e smontare dopo essere stato cercato.
xenoterracide,

@xenoterracide: Ancora una volta: no, non è necessario montarli singolarmente. Il flusso di lavoro completo (oltre all'installazione di AVFS se necessario) è nei miei frammenti di codice.
Gilles 'SO- smetti di essere malvagio'

@gilles bene dovrò scavare un po 'in questo ... perché ottengo find: missing argument to -exec' 'e molto di questo da zshzsh: Input/output error: Data-Maker-0.27
xenoterracide

0

Sembra che posso farlo in questo modo

find authors/ -type f -exec zgrep "Test::Version" '{}' +  

Tuttavia, questo dà risultati come:

authors/id/J/JO/JONASBN/Module-Info-File-0.11.tar.gz:Binary file (standard input) matches

che non è molto specifico di dove nel tarball. Spero che qualcuno possa trovare una risposta migliore.


0

Grazie per la sfida, mi sono inventato:

#!/bin/bash
#

# tarballs to check in
find authors/ -type f | while read tarball; do

    # get list of files in tarball (not dirs ending in /):
    tar tzf $tarball | grep -v '/$' | while read file; do       

        # get contents of file and look for string
        tar -Ozxf conform.tar.gz $file | grep -q 'Text::Version' && echo "Tar ($tarball) has matching File ($file)"

    done

done

Ho appena visto il tuo numero di riga richiesto. Ciò può probabilmente funzionare con una combinazione di grep -n e awk per acquisire il numero di riga. Non può essere semplice come grep -H per elencare il nome del file poiché è sempre stdin, quindi potrebbe richiedere più righe.
Kyle Smith,

errori fuori esecuzione sul mio sistema, infinito ripetuto:tar (child): conform.tar.gz: Cannot open: No such file or directory tar (child): Error is not recoverable: exiting now tar: Child returned status 2 tar: Error is not recoverable: exiting now
xenoterracide

inoltre non mi sono reso conto quando ho pubblicato per la prima volta che alcuni degli archivi su cpan sono file zip.
xenoterracide,

Hm, ho testato con una struttura di soli file .tar.gz - potrebbe essere reso più robusto intraprendere azioni appropriate in base al tipo di file, ma questo dovrebbe dare un buon punto di partenza.
Kyle Smith,

0

Forse la mia risposta sarà utile per qualcuno:

#!/bin/bash

findpath=$(echo $1 | sed -r 's|(.*[^/]$)|\1/|')

# tarballs to check in
find $findpath -type f | while read tarball; do

    # get list of files in tarball (not dirs ending in /):
    if [ -n "$(file --mime-type $tarball | grep -e "application/jar")" ]; then

        jar tf $tarball | grep -v '/$' | while read file; do
            # get contents of file and look for string
            grepout=$(unzip -q -c $tarball $file | grep $3 -e "$2")

            if [ -n "$grepout" ]; then
                echo "*** $tarball has matching file ($file):"
                echo $grepout
            fi

        done

    elif tar -tf $tarball 2>/dev/null; then

        tar -tf $tarball | grep -v '/$' | while read file; do
            # get contents of file and look for string
            grepout=$(unzip -q -c $tarball $file | grep $3 -e "$2")

            if [ -n "$grepout" ]; then
                echo "*** $tarball has matching file ($file):"
                echo $grepout
            fi

        done

    else
        file=""
        grepout=$(grep $3 -e "$2" $tarball)

        if [ -n "$grepout" ]; then
            echo "*** $tarball has matching:"
            echo $grepout
        fi

    fi

done

0

Dopo l'installazione p7zip-*sei in grado di fare questo:

ls | xargs -I {} 7z l {} | grep whatever | less

Non è necessario utilizzare lsprima della prima pipe, indipendentemente dall'elenco in cui funzioneranno i file compressi. Solo il finale lessmostrerà il PERCORSO della vita del listet all'interno dell'archivio compresso, ma non il nome di questo.


0

Utilizzare find per individuare tutti i file necessari e zgrep per esaminare i file compressi:

find <folder> -type f -name "<search criteria[*gz,*bz...]>" -execdir zgrep -in "<grep expression>" '{}' ';'

Tuttavia, non ho provato questo su tarball

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.