Passando più directory all'opzione -prune in find


9

Sto usando findper individuare ed eliminare i file di backup, ma desidero escludere determinate directory dalla ricerca. I nomi dei file di backup possono terminare in .bck, bak, ~o backup.

Il codice di esempio di lavoro minimo (MWE) con solo tre directory da escludere è:

#! /bin/bash
find . -type d \( -path "./.*" -o -path "./Music" -o -path "./Documents" \) -prune -o -type f \( -name "*.bck" -o -name "*.bak" -o -name "*~" -o -name "*.backup" \) -print0 | xargs -0 --no-run-if-empty trash-put

La sintassi \( -path "dir1" -o -path "dir2" ... -o -path "dirN" \) -prunesembra un po 'goffa, specialmente se ci sono circa dieci directory da escludere, anche se ne ho mostrate solo tre nel MWE.

Esiste un modo più elegante utilizzando un file di input, con l'elenco di directory escluse o un costrutto simile a un array o a una lista, che potrebbe essere messo in servizio?

Mi dispiace di non essere più esplicito quando ho scritto la mia domanda originale.

NB: trash-putè un'utilità che sposta i file in Trashcaninvece di eliminarli [1].

[1]. https://github.com/andreafrancia/trash-cli

Risposte:


4

Per quanto ne so, non esiste alcuna opzione per dire finddi leggere schemi da un file. Una soluzione semplice è quella di salvare i pattern che voglio escludere in un file e passare quel file come input per un contrario grep. Ad esempio, ho creato i seguenti file e directory:

$ tree -a
.
├── a
├── .aa
├── .aa.bak
├── a.bck
├── b
├── .dir1
│   └── bb1.bak
├── dir2
│   └── bb2.bak
├── b.bak
├── c
├── c~
├── Documents
│   └── Documents.bak
├── exclude.txt
├── foo.backup
└── Music
    └── Music.bak

Se ho capito l'esempio che hai postato correttamente, si desidera spostare a.bck, .aa.bak, b.bak, c~, foo.backupe dir2/bb2.bakper la spazzatura e ferie .aa.bak, .dir1/bb1.bak, Documents/Documents.bake Music/Music.bakdove si trovano. Pertanto, ho creato il file exclude.txtcon i seguenti contenuti (puoi aggiungerne quanti ne vuoi):

$ cat exclude.txt 
./.*/
./Music
./Documents

Uso ./.*/perché ho capito che la tua scoperta originale significa che vuoi spostare i file di backup nascosti ( .foo) che si trovano nella directory corrente ma escludere tutti i file di backup che si trovano nelle directory nascoste ( .foo/bar). Quindi, ora posso eseguire il findcomando e utilizzare grepper escludere file indesiderati:

$ find . -type f | grep -vZf exclude.txt | xargs -0 --no-run-if-empty trash-put

Opzioni grep:

   -v, --invert-match
          Invert  the  sense  of matching, to select non-matching
          lines.  (-v is specified by POSIX.)
   -f FILE, --file=FILE
          Obtain patterns from FILE, one  per  line.   The  empty
          file  contains  zero  patterns,  and  therefore matches
          nothing.  (-f is specified by POSIX.)
   -Z, --null
          Output a zero byte (the ASCII NUL character) instead of
          the  character  that normally follows a file name.  For
          example, grep -lZ outputs a zero byte after  each  file
          name  instead  of the usual newline.  This option makes
          the output unambiguous, even in the  presence  of  file
          names  containing  unusual  characters  like  newlines.
          This  option  can  be  used  with  commands  like  find
          -print0,  perl  -0,  sort  -z,  and xargs -0 to process
          arbitrary file names, even those that  contain  newline
          characters.

Mi dispiace così tanto per non essere esplicito. Si prega di vedere la domanda rivista che spero sia più chiara.
chandra,

@chandra vedi risposta aggiornata, stessa idea generale, dettagli diversi.
terdon

Grazie. Hai risposto alla mia domanda in modo molto chiaro e perfetto per il mio scopo. Ho accettato la tua risposta
chandra,

6

Con GNU find (cioè sotto Linux o Cygwin non incorporato), puoi usare -regexper combinare tutti questi -pathcaratteri jolly in un unico regex.

find . -regextype posix-extended \
     -type d -regex '\./(\..*|Music|Documents)' -prune -o \
     -type f -regex '.*(\.(bck|bak|backup)|~)' -print0 |
xargs -0 --no-run-if-empty trash-put

Con FreeBSD o OSX, usa -Einvece di -regextype posix-extended.


Grazie per un'eccellente risposta alternativa. È un peccato non poter accettare due risposte.
chandra,

2

Raggruppa -path ... -prunein un'espressione racchiusa \( ... \)usando -o( o ) la logica.

find /somepath \( -path /a -prune -o \
                  -path /b -prune -o \
                  -path /c -prune \
               \) \
               -o -print

L'esempio directory o file in o sotto non iterazione /somepath/a, /somepath/be /somepath/c.

Ecco un esempio più specifico che utilizza più azioni.

find / \( -path /dev -prune -o \
          -path /proc -prune -o \
          -path /sys -prune \
       \) \
       -o -printf '%p ' -exec cksum {} \;

1

Questa sembra essere più una domanda shell che una finddomanda. Con un file contenente ( -name dir1 -o -name dir2 ) -prune(no "\"!) Puoi semplicemente fare questo:

find ... $(< /path/to/file)

Senza cambiare la chiamata find stessa ( eval findo cambiando $ IFS), tuttavia, funziona con percorsi senza spazi bianchi.

Se vuoi mantenere il file più semplice puoi scrivere uno script.

# file content
dir1
dir2
dir3

# script content
#!/bin/bash
file=/path/to/file
# file may be checked for whitespace here
grep '[^[:space:]]' "$file" | { empty=yes
  while read dir; do
    if [ yes = "$empty" ]; then
      echo -n "( "
      empty=no
    else
      echo -n " -o "
    fi
    echo -n "-name ${dir}"
  done
  if [ no = "$empty" ]; then
    echo -n " ) -prune"
  fi; }

E usare

find ... $(/path/to/script)

anziché.


Mi dispiace così tanto per non essere esplicito. Si prega di vedere la domanda rivista che spero sia più chiara.
chandra,

@chandra Non vedo come la tua domanda sia più chiara né capisco quale potrebbe essere un problema con la mia soluzione (ad eccezione del banale rimpiazzo di -nameby path).
Hauke ​​Laging,

La mia sceneggiatura sopra funziona e fa quello che voglio. Volevo semplicemente sapere se c'era un modo più ordinato di \( -path "dir1" -o -path "dir2" ... -o -path "dirN" \) -pruneescludere determinate directory dalla ricerca ricorsiva che findfa. Non sto cercando nulla all'interno dei file, ma piuttosto eliminando determinati file ed evitando determinate directory nel mio percorso di ricerca. Non capisco nemmeno cosa stia cercando di fare la tua sceneggiatura. Quindi, sembra che abbiamo una cattiva comunicazione. Scusate. Lasciamolo a quello.
chandra,
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.