Il problema con il tentativo originale:
find www/*.html -type f -exec sh -c "echo $(basename {})" \;
è che il codice $(basename {})
viene eseguito una volta, prima dell'esecuzione del comando find
buito. L'output del singolo basename
è {}
poiché quello è il nome di base di {}
come nome file. Così, il comando che viene eseguito dal ritrovamento è:
sh -c "echo {}"
per ogni file trovato, ma find
sostituisce in realtà il nome del file (non modificato) originale ogni volta perché i {}
personaggi appaiono nella stringa da eseguire.
Se si voleva farlo funzionare, è possibile utilizzare le virgolette singole al posto delle virgolette:
find www/*.html -type f -exec sh -c 'echo $(basename {})' \;
Tuttavia, rendendo echo
ripetere sullo standard output quello basename
avrei scritto sullo standard output in ogni caso è un po 'inutile:
find www/*.html -type f -exec sh -c 'basename {}' \;
e siamo in grado di ridurre ulteriormente che, naturalmente, a:
find www/*.html -type f -exec basename {} \;
Potresti anche spiegare la differenza tra virgolette singole e virgolette doppie qui?
Questo è un comportamento di shell di routine. Prendiamo un comando leggermente diverso (ma solo leggermente - i nomi dei file potrebbero essere ovunque sotto la directory www
, non solo di un livello inferiore), e guardiamo le versioni a virgolette singole (SQ) e doppie quote (DQ) di il comando:
find www -name '*.html' -type f -exec sh -c "echo $(basename {})" \; # DQ
find www -name '*.html' -type f -exec sh -c 'echo $(basename {})' \; # SQ
Le virgolette singole passano il materiale allegato direttamente al comando.Così, nella riga di comando SQ, la shell che lancia find
rimuove le virgolette che racchiudono e il comando find
vede il suo argomento $9
come:
echo $(basename {})
perché la shell rimuove le virgolette. In confronto, il materiale tra virgolette viene elaborato dalla shell. Così, nella riga di comando DQ, il guscio (che lancia find
- non quella lanciata dafind
) vede la parte $(basename {})
della stringa e lo esegue, tornando {}
, quindi la stringa si passa alla find
come argomento $9
è:
echo {}
Ora, quando fa il suo find
-exec
azione, in entrambi i casi sostituisce il {}
dal nome del file che appena trovato (per amor di discussione, www/pics/index.html
). Così, si ottiene due comandi diversi in corso di esecuzione:
sh -c 'echo $(basename www/pics/index.html)' # SQ
sh -c "echo www/pics/index.html" # DQ
C'è una (lieve) imbroglio notazione succedendo lì - quelli sono i comandi equivalenti che devi digitare in corrispondenza dello scafo. Lo $2
della shell che viene lanciata in realtà non contiene virgolette in entrambi i casi: la shell lanciata non vede alcuna virgoletta.
Come si può vedere, il comando DQ fa semplicemente eco al nome del file; il comando SQ esegue il comando basename
e ne cattura l'output, quindi esegue l'eco dell'output acquisito. Un po 'di pensiero riduzionista mostra che il comando DQ potrebbe essere scritto come -print
invece di usare -exec
e il comando SQ potrebbe essere scritto come -exec basename {} \;
.
Se stai usando GNU find
, supporta l'azione -printf
che può essere seguita da Format Directives tale che l'esecuzione basename
non è necessaria. Tuttavia, questo è disponibile solo in GNU find
; il resto della discussione qui si applica a qualsiasi versione di find
che è probabile incontrare.
Questa è un'ottima risposta e spiegazione. Potresti anche spiegare la differenza tra virgolette singole e doppie virgolette qui? –
Grazie mille per aver aggiunto le informazioni sulle citazioni –
Non c'è ovviamente alcun motivo per usare 'sh -c' qui, ma' -exec sh -c 'echo "$ (basename" {} ")"' \; ', dovrebbe ancora includere virgolette per impedire la suddivisione in parole. in tal caso, '-exec sh -c 'echo" $ (basename "$ 1") "' sh {} \;' sarebbe davvero preferibile. – BroSlow