Mám příkaz find, který najde určité soubory a adresáře. Tento příkaz find poté spustí rsync se soubory a adresáři nalezenými dříve jako zdroj. Problém je v tom, že tyto soubory a adresáře mohou mít nejrůznější znaky, jako jsou jednoduché a dvojité uvozovky, nemluvě o nelegálních znacích z Windows atd…
Jak mohu dynamicky escapovat řetězec pro použití v rsync nebo jiných příkazech?
Tento příkaz funguje tak, že pevně zakóduje dvojité uvozovky pro zdrojový řetězec rsync, ale přeruší se, pokud řetězec obsahuje dvojité uvozovky.
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}" \; \)
výsledný výstup:
rsync -i -dIWRpEAXogt --numeric-ids --inplace --dry-run "test/this " is an issue" /mnt/backing
Pracovní příkaz po použití informací v odpovědích:
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 {} \; \)
Přijatá odpověď:
Váš problém s citováním pochází z toho, že se snažíte vyřešit problém, který nemáte. Potřeba citovat argumenty přichází do hry pouze tehdy, když máte co do činění s shellem a pokud find
volá rsync
přímo, není zapojen žádný shell. Použití vizuálního výstupu není dobrý způsob, jak zjistit, zda funguje nebo ne, protože nevidíte, kde každý argument začíná a končí.
Zde je to, co mám na mysli:
# 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: -
Všimněte si, že jsem necitoval {}
v argumentu stat
.
Nyní, když bylo řečeno, váš příkaz bude velmi nevýkonný, protože voláte rsync
pro každý odpovídající soubor. Existují 2 způsoby, jak to můžete vyřešit.
Jak uvedli jiní, můžete použít kanál se seznamem souborů k rsync
na stdin:
# find . -type f -print0 | rsync --files-from=- -0 . dest/
# ls dest/
foo'"bar
Tím se jako oddělovač názvu souboru použijí prázdné bajty, protože soubory nemohou ve svém názvu obsahovat prázdné bajty.
Související:Jak opravit chybu „Neznámé zařízení USB potřebuje více energie, než může port dodat“?
Pokud používáte GNU, find
, máte jiný způsob vyvolání -exec
a to je -exec {} +
. V tomto stylu find
projde více než jedním argumentem najednou. Všechny argumenty se však přidávají na konec příkazu, nikoli doprostřed. Můžete to vyřešit předáním argumentů přes malý shell:
# find . -type f -exec sh -c 'rsync "[email protected]" dest/' {} +
# ls dest/
foo'"bar
Tím předáte seznam souborů do sh
které je poté nahradí za "[email protected]"