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.