Trova ricorsivamente tutti i file di archivio di diversi formati di archivio e cercali per i modelli di nomi di file


11

Nella migliore delle ipotesi, vorrei ricevere una chiamata come questa:

$searchtool /path/to/search/ -contained-file-name "*vacation*jpg"

... in modo che questo strumento

  • esegue una scansione ricorsiva del percorso indicato
  • prende tutti i file con formati di archivio supportati che dovrebbero almeno essere i "più comuni" come zip, rar, 7z, tar.bz, tar.gz ...
  • ed esegue la scansione dell'elenco dei file dell'archivio per il modello di nome in questione (qui *vacation*jpg)

Sono a conoscenza di come utilizzare lo strumento Trova, tar, decomprimere e simili. Potrei combinarli con uno script di shell ma sto cercando una soluzione semplice che potrebbe essere una shell one-liner o uno strumento dedicato (i suggerimenti per gli strumenti della GUI sono i benvenuti ma la mia soluzione deve essere basata sulla riga di comando).

find  tar  zip  7z  rar 

Risposte:


9

(Adattato da Come posso ricorrere in modo ricorsivo agli archivi compressi? )

Installa AVFS , un filesystem che fornisce accesso trasparente all'interno degli archivi. Innanzitutto eseguire questo comando una volta per impostare una vista del filesystem della macchina in cui è possibile accedere agli archivi come se fossero directory:

mountavfs

Dopodiché, se /path/to/archive.zipè un archivio riconosciuto, allora ~/.avfs/path/to/archive.zip#è una directory che sembra contenere il contenuto dell'archivio.

find ~/.avfs"$PWD" \( -name '*.7z' -o -name '*.zip' -o -name '*.tar.gz' -o -name '*.tgz' \) \
     -exec sh -c '
                  find "$0#" -name "*vacation*.jpg"
                 ' {} 'Test::Version' \;

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

O in zsh ≥4.3:

mountavfs
ls -l ~/.avfs$PWD/**/*.(7z|tgz|tar.gz|zip)(e\''
     reply=($REPLY\#/**/*vacation*.jpg(.N))
'\')

spiegazioni:

  • ~/.avfs$PWD/**/*.(7z|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\#/**/*vacation*.jpgcorrisponde ai *vacation*.jpgfile nell'archivio.
  • Il Nqualificatore glob fa espandere il modello in un elenco vuoto se non c'è corrispondenza.

9

Se vuoi qualcosa di più semplice della soluzione AVFS, ho scritto uno script Python per farlo chiamato arkfind . In realtà puoi semplicemente farlo

$ arkfind /path/to/search/ -g "*vacation*jpg"

Lo farà in modo ricorsivo, quindi puoi guardare gli archivi all'interno degli archivi a una profondità arbitraria.


Grazie, bel contributo! Soprattutto se AVFS non è un'opzione.
MDO

Sarebbe bello se supporta i file jar.
Chemik,

@Chemik - notato ! Ci lavorerò un po 'di più questo fine settimana :) JAR non dovrebbe essere troppo difficile, credo che sia davvero solo un file zip per il mondo esterno.
detly

@Chemik - L'ho appena provato e dovrebbe comunque supportare i file JAR nella sua forma attuale. Puoi provarlo e, se non funziona come previsto, presentare un bug sulla pagina di Github? (Ho appena corretto un bug, quindi assicurati di aggiornare la tua copia.)
Detly

1
Sì, vedo ora, funziona. È possibile aggiungere "file JAR" a README :)
Chemik,

2

La mia solita soluzione:

find -iname '*.zip' -exec unzip -l {} \; 2>/dev/null | grep '\.zip\|DESIRED_FILE_TO_SEARCH'

Esempio:

find -iname '*.zip' -exec unzip -l {} \; 2>/dev/null | grep '\.zip\|characterize.txt'

I risultati sono come:

foozip1.zip:
foozip2.zip:
foozip3.zip:
    DESIRED_FILE_TO_SEARCH
foozip4.zip:
...

Se vuoi solo il file zip con hit su di esso:

find -iname '*.zip' -exec unzip -l {} \; 2>/dev/null | grep '\.zip\|FILENAME' | grep -B1 'FILENAME'

FILENAME qui viene usato due volte, quindi puoi usare una variabile.

Con find potresti usare PATH / TO / SEARCH


2

Un'altra soluzione che funziona è zgrep

zgrep -r filename *.zip

1
Di quale implementazione si zgreptratta? Questo non funziona con quello fornito con GNU gzip( /bin/zgrep: -r: option not supported, zgrep (gzip) 1.6)
Stéphane Chazelas,

2

Anche la facilità d'uso di IMHO dovrebbe essere una cosa da bash:

 while read -r zip_file ; do echo "$zip_file" ; unzip -l "$zip_file" | \
 grep -i --color=always -R "$to_srch"; \
 done < <(find . \( -name '*.7z' -o -name '*.zip' \)) | \
 less -R

e per tar (questo non è testato ...)

 while read -r tar_file ; do echo "$tar_file" ; tar -tf  "$tar_file" | \
 grep -i --color=always -R "$to_srch"; \
 done < <(find . \( -name '*.tar.gz' -o -name '*.tar' \)) | \
 less -R

Quale unzipimplementazione può gestire i file 7z o tar.gz?
Stéphane Chazelas,

sì, questo è un bug ... corretto ... uno dovrebbe sicuramente usare i binari corretti per i tipi di file corretti ... Ho solo mirato a dimostrare il one-liner .. jee questo quasi arriverà allo stato di essere pronto come ricevuta di istruzioni ...
Yordan Georgiev,

0

libarchiveè in bsdtargrado di gestire la maggior parte di quei formati di file, quindi puoi fare:

find . \( -name '*.zip' -o     \
          -name '*.tar' -o     \
          -name '*.tar.gz' -o  \
          -name '*.tar.bz2' -o \
          -name '*.tar.xz' -o  \
          -name '*.tgz' -o     \
          -name '*.tbz2' -o    \
          -name '*.7z' -o      \
          -name '*.iso' -o     \
          -name '*.cpio' -o    \
          -name '*.a' -o       \
          -name '*.ar' \)      \
       -type f                 \
       -exec bsdtar tf {} '*vacation*jpg' \; 2> /dev/null

Che puoi semplificare (e migliorare per far corrispondere maiuscole e minuscole) con GNU findcon:

find . -regextype egrep \
       -iregex '.*\.(zip|7z|iso|cpio|ar?|tar(|\.[gx]z|\.bz2)|tgz|tbz2)' \
       -type f \
       -exec bsdtar tf {} '*vacation*jpg' \; 2> /dev/null

Ciò non stampa il percorso dell'archivio in cui *vacation*jpgsi trovano quei file. Per stampare quel nome è possibile sostituire l'ultima riga con:

-exec sh -ac '
   for ARCHIVE do
     bsdtar tf "$ARCHIVE" "*vacation*jpg" |
       awk '\''{print ENVIRON["ARCHIVE"] ": " $0}'\''
   done' sh {} + 2> /dev/null

che fornisce un output come:

./a.zip: foo/blah_vacation.jpg
./a.zip: bar/blih_vacation.jpg
./a.tar.gz: foo/blah_vacation.jpg
./a.tar.gz: bar/blih_vacation.jpg

O con zsh:

setopt extendedglob # best in ~/.zshrc
for archive (**/*.(#i)(zip|7z|iso|cpio|a|ar|tar(|.gz|.xz|.bz2)|tgz|tbz2)(.ND)) {
  matches=("${(f@)$(bsdtar tf $archive '*vacation*jpg' 2> /dev/null)"})
  (($#matches)) && printf '%s\n' "$archive: "$^matches
}

Nota che ci sono un certo numero di altri formati di file che sono giusti zipo tgzfile sotto mentite spoglie .jaro .docxfile. Puoi aggiungerli al tuo modello find/ zshsearch, bsdtarnon importa l'estensione (come in, non si basa sull'estensione per determinare il tipo di file).

Si noti che *vacation*.jpgsopra corrisponde al percorso completo del membro dell'archivio, non solo al nome del file, quindi corrisponderebbe a vacation.jpgma anche a vacation/2014/file.jpg.

Per abbinare solo il nome del file, un trucco sarebbe usare la modalità di estrazione , usare -s(sostituzione) che usa regexps con un pflag per stampare i nomi dei file corrispondenti e quindi assicurarsi che nessun file sia estratto, come:

bsdtar -'s|.*vacation[^/]*$||' -'s|.*||' -xf "$archive"

Notare che avrebbe generato l'elenco su stderr e aggiunto >>a ogni riga. In ogni caso, bsdtarcome la maggior parte delle tarimplementazioni possono alterare i nomi dei file visualizzati se contengono alcuni caratteri come newline o barra rovesciata (renderizzati come \no \\).

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.