Comprensione dell'opzione -exec di find (1) (parentesi graffe e segno più)


17

Utilizzando il seguente comando, qualcuno potrebbe spiegare qual è esattamente lo scopo delle parentesi graffe finali ({}) e del segno più (+)?

E come avrebbe funzionato diversamente il comando se fossero stati esclusi dal comando?

find . -type d -exec chmod 775 {} +

Risposte:


19

Le parentesi graffe verranno sostituite dai risultati del findcomando e chmodverranno eseguite su ciascuna di esse. I +marchi findtenta di eseguire il minor numero possibile di comandi (così, chmod 775 file1 file2 file3a differenza chmod 755 file1, chmod 755 file2, chmod 755 file3). Senza di essi il comando dà solo un errore. Questo è tutto spiegato in man find:

-exec command ;

      Esegui comando ; vero se viene restituito lo stato 0. Tutti i seguenti argomenti finddevono essere considerati argomenti per il comando fino a quando non ;viene rilevato un argomento costituito da " ". La stringa ' {}' viene sostituita dal nome del file corrente che viene elaborato ovunque si presenti negli argomenti del comando, non solo negli argomenti in cui è solo, come in alcune versioni di find. ...

-exec command {} +

      Questa variante -execdell'azione esegue il comando specificato sui file selezionati, ma la riga di comando viene creata aggiungendo alla fine ciascun nome di file selezionato; il numero totale di invocazioni del comando sarà molto inferiore al numero di file corrispondenti. ...


12

Oltre alla risposta di Terdon,

  • "Ovviamente" -exec …deve essere terminato con un punto e virgola ( ;) o un segno più ( +). Punto e virgola è un carattere speciale nella shell (o, almeno, ogni shell che abbia mai usato), quindi, se è per essere utilizzato come parte del findcomando , deve essere sfuggito o citato ( \;, ";", o ';').
  • Con -exec … ;, la {}stringa può apparire un numero qualsiasi di volte nel comando, incluso zero , o due o più, in qualsiasi posizione.  Vedi questo per un esempio del perché potresti voler fare a -execmeno di usare {}.   Avere due o più apparizioni è utile principalmente perché, in (almeno) alcune versioni di find, {}non è necessario che sia una parola da sola; può avere altri personaggi all'inizio o alla fine; per esempio,

    find . -type f -exec mv {} {}.bak ";"
    

    Con -exec … +, la {}stringa deve apparire come ultimo argomento prima del +. Un comando simile

    find . -name "*.bak" -exec mv {} backup_folder +
    

    provoca il find: missing argument to ‘-exec’messaggio enigmatico di errore.

    • Una soluzione alternativa per questo che è specifica per i comandi cpe mvè

      find . -name "*.bak" -exec mv -t backup_folder {} +
      

      o

      find . -name "*.bak" -exec mv --target-directory=backup_folder {} +
      

    La {}deve essere una parola di per sé; non può avere altri personaggi all'inizio o alla fine. E, in (almeno) alcune versioni di find, potresti non averne più di una {}.

  • Una nota di sanità mentale: puoi dire

    trova . -name "* .sh" -type f -executable -exec {} args opzionale qui ";"

    per eseguire ciascuno dei tuoi script. Ma

    trova . -name "* .sh" -type f -executable -exec {} +

    esegue uno dei tuoi script, con i nomi di tutti gli altri come parametri. Questo è simile al dire

    ./*.sh
    

    come comando shell, tranne findche non garantisce che ordina i suoi risultati, quindi non sei garantito per l'esecuzione aaa.sh (il tuo primo *.shfile in ordine alfabetico ) come saresti con l'esecuzione ./*.sh.

  • Un aspetto findche potrebbe non essere perfettamente chiaro ai principianti è che la riga di comando è, in effetti, un'istruzione eseguibile in un linguaggio arcano. Per esempio,

    find . -name "*.sh" -type f -executable -print
    

    si intende

    for each file
        if the file’s name matches `*.sh` (i.e., if it ends with `.sh`)
        then
            if it is a plain file (i.e., not a directory)
            then
                if it is executable (i.e., the appropriate `---x--x--x` bit is set)
                then
                    print the file’s name
                end if
            end if
        end if
    end loop
    

    o, semplicemente,

    for each file
        if the file’s name matches `*.sh`  AND  it is a plain file  AND  it is executable
        then
            print the file’s name
        end if
    end loop
    

    Alcune delle -parole chiave sono sia un'azione eseguibile che un test. In particolare, questo è vero per -exec … ;; per esempio,

    find . -type f -exec grep -q cat {} ";" -print
    

    si traduce in

    per ogni file
        se è un file semplice (cioè non una directory)
        poi
            esegue grep -q cat nomefile
            se il processo ha esito positivo (ovvero, esce con stato 0)
            poi
                stampa il nome del file
            finisci se
        finisci se
    end loop

    che stamperà i nomi di tutti i file contenenti la stringa “ cat”. E, mentre questo è qualcosa che greppuò fare da solo (con l' opzione -l(lettere minuscole L), può essere utile usarlo con findper trovare file che contengono una determinata stringa E hanno una certa dimensione E sono di proprietà di un determinato proprietario E sono stati modificati in un determinato intervallo di tempo, ....

    Tuttavia, questo non funziona per -exec … +. Poiché -exec … +esegue un comando per più file, non ha senso usarlo come condizione logica all'interno di un for each file …ciclo.

  • Il rovescio della medaglia di quanto sopra è che findgeneralmente esce con uno stato di uscita pari a 0 a meno che non gli dia argomenti non validi o incontri una directory che non può leggere. Anche se un programma che si esegue ha esito negativo (esce con uno stato di uscita diverso da zero), finduscirà con uno stato di uscita pari a 0.  Tranne  se un programma che si esegue con -exec … +esito negativo (esce con uno stato di uscita diverso da zero), finduscirà con uno stato di uscita diverso da zero.

Oltre a un milione di versioni find(1) e test di ciò che findeffettivamente fa su un paio di sistemi, The Open Group Base Specifiche Edizione 7, 2013 Edition ha fornito alcune delle informazioni su ciò che finddeve, può e non deve fare.


3
Fai attenzione che il tuo esempio usando ... -exec mv {} {}.bak ...non è garantito per funzionare come previsto con tutte le findimplementazioni. Gli stati standard POSIX {}devono apparire da soli per essere sempre riconosciuti, altrimenti il ​​comportamento è libero di mantenere invariati i caratteri o di sostituirli con il nome del percorso. Nel primo caso, l'intero comando eliminerà essenzialmente tutti i file ma l'ultimo trovato ...
jlliagre,
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.