Ho un comando di ricerca che trova determinati file e directory. Il comando find esegue quindi rsync con i file e le directory trovati in precedenza come origine. Il problema è che quei file e directory possono avere tutti i tipi di caratteri come virgolette singole e doppie per non parlare dei caratteri illegali di Windows ecc...
Come posso eseguire l'escape dinamico di una stringa da utilizzare in rsync o altri comandi?
Questo comando funziona codificando a fondo le virgolette doppie per la stringa sorgente rsync, ma si interromperà se la stringa contiene virgolette doppie.
find "/mnt/downloads/cache/" -depth -mindepth 1 \( \
-type f \! -exec fuser -s '{}' \; -o \
-type d \! -empty \) \
\( -exec echo rsync -i -dIWRpEAXogt --numeric-ids --inplace --dry-run '"{}"' "${POOL}" \; \)
output risultante:
rsync -i -dIWRpEAXogt --numeric-ids --inplace --dry-run "test/this " is an issue" /mnt/backing
Comando di lavoro dopo le informazioni nelle risposte applicate:
find "/mnt/downloads/cache/" -depth -mindepth 1 \( \
-type f \! -exec fuser -s {} \; -o \
-type d \! -empty \) \
\( -exec rsync -i -dIWRpEAXogt --remove-source-files-- "${POOL} \; \) \
-o \( -type d -empty -exec rm -d {} \; \)
Risposta accettata:
Il tuo problema di quotazione viene da te che cerchi di risolvere un problema che non hai. La necessità di citare gli argomenti entra in gioco solo quando hai a che fare con una shell e se find
sta chiamando rsync
direttamente, non è coinvolta alcuna shell. L'uso dell'output visivo non è un buon modo per sapere se funziona o meno perché non puoi vedere dove inizia e dove finisce ogni argomento.
Ecco cosa intendo:
# touch "foo'\"bar"
# ls
foo'"bar
# find . -type f -exec stat {} \;
File: ‘./foo'"bar’
Size: 0 Blocks: 0 IO Block: 4096 regular empty file
Device: fd00h/64768d Inode: 1659137 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 1004/ phemmer) Gid: ( 1004/ phemmer)
Access: 2017-12-09 13:21:28.742597483 -0500
Modify: 2017-12-09 13:21:28.742597483 -0500
Change: 2017-12-09 13:21:28.742597483 -0500
Birth: -
Nota che non ho citato il {}
nell'arg a stat
.
Detto questo, il tuo comando sarà molto poco performante, perché stai chiamando rsync
per ogni singolo file corrispondente. Ci sono 2 modi per risolverlo.
Come altri hanno indicato, puoi usare pipe l'elenco dei file su rsync
su stdin:
# find . -type f -print0 | rsync --files-from=- -0 . dest/
# ls dest/
foo'"bar
Questo utilizzerà i byte nulli come delimitatore del nome del file poiché i file non possono contenere byte nulli nel loro nome.
Correlati:come correggere l'errore "Il dispositivo USB sconosciuto ha bisogno di più energia di quella che la porta può fornire"?
Se stai usando GNU find
, hai un altro metodo per invocare -exec
, e questo è -exec {} +
. In questo stile find
passerà più di un argomento alla volta. Tuttavia, tutti gli argomenti vengono aggiunti alla fine del comando, non nel mezzo. Puoi risolvere questo problema passando gli argomenti attraverso una piccola shell:
# find . -type f -exec sh -c 'rsync "[email protected]" dest/' {} +
# ls dest/
foo'"bar
Questo passerà l'elenco dei file a sh
che li sostituirà con "[email protected]"