Как правильно экранировать странные символы в сценарии bash?

readlink ожидает символическую ссылку, а затем отображает файл/дир, на который указывает символическая ссылка.

  • в вашей первой попытке: он видит символическую ссылку, поэтому отображает то, на что она указывает
  • во второй попытке: он видит music/., что является Music/., который является указанным каталогом, а не символической ссылкой, указывающей на этот каталог, поэтому у него нет ссылки для интерпретации. (Другими словами, когда вы добавляете конечное "/", дескриптор файла оболочки вместо этого предназначен для указанного каталога).
5
29.08.2017, 15:46
3 ответа

Не усложняйте чем это должно быть.

find /home/jason/gPodder/ -name '*.mp3' -exec cp {} /home/jason/gPodder/mp3/ \;

или, возможно,

find /home/jason/gPodder/ -type f -name '*.mp3' -exec cp {} /home/jason/gPodder/mp3/ \;

, чтобы рассматривать только обычные файлы.

Чтобы скопировать файл только в том случае, если в папке назначения уже нет файла с таким именем, некоторые реализации cpподдерживают для этого параметр -n, или вы можете использовать -iсо стандартным вводом, перенаправленным из /dev/null(но будьте осторожны, они не работают, если целью является тип каталога) или сделайте что-то вроде:

find /home/jason/gPodder/ -type f -name '*.mp3' \
    ! -execdir test -e /home/jason/gPodder/mp3/{} \; \
    -exec cp {} /home/jason/gPodder/mp3/ \;

-execdirявляется расширением стандарта POSIX find, но поддерживается многими современными реализациями find. Он работает как -exec, но выполняет команду с родительским каталогом найденного объекта в качестве рабочего каталога. Кроме того, {}будет базовым именем найденной вещи (либо file.mp3, либо ./file.mp3в зависимости от реализации find), а не полный путь к нему. См. man find.


Ошибка связана с bash "somecommand". При вызове bashтаким образом, bashожидает, что somecommandбудет путем к файлу сценария, а не последовательностью команд оболочки, и не может найти сценарий с именем, которое вы ему даете.

Чтобы выполнить произвольную серию команд оболочки, вам нужно bash -c "somecommand".

Но в этом случае просто используйте -exec cp, как указано выше, или как в ответе Stéphane Chazelas.

6
27.01.2020, 20:33

Другие указали на проблемы с цитированием и выполнением.

Я предлагаю вам не использовать find -exec, а вместо этого найти список файлов и передать этот список в xargs и cp. Использование опции print0 поможет вам обойти любые «забавные» символы в именах файлов и каталогов

, например.

find sourcepath -name \*.mp3 -print0 \
    | xargs -0 cp -t destinationpath

Преимущество этого заключается в том, что xargs будет собирать несколько имен файлов вместе из find и одновременно передавать их в cp, поэтому каждый экземпляр cp может копировать 20 или 100 файлов, а не запускать 1 вызов cp для каждого файла. xargs позаботится о том, чтобы вставить достаточное количество имен файлов в командную строку cp.

Вы также можете добавить параметр -P n к xargs, и он запустит несколько процессов cp параллельно.

На том основании, что ваши файлы находятся в той же файловой системе, что и целевая папка mp3. Вы можете добавить -l к cp, и он жестко свяжет файлы с местом назначения, а не копирует их.

напр.

find sourcepath -name \*.mp3 -print0 \
    | xargs -0 -P 5 \
    cp -l -t destinationpath
0
27.01.2020, 20:33

Как @Kusalananda сказал , вам не хватает -c, чтобы иметь возможность использовать встроенный -скрипт.

Но даже в этом случае никогда не встраивайте {}в шелл-код, это может привести к уязвимости, связанной с внедрением произвольной команды (подумайте, например, о файле с именем '$(reboot)'.mp3в вашем примере ). Вместо этого сделайте его аргументом встроенного скрипта (, предполагая, что вам здесь нужен встроенный скрипт, а cp— это просто пример ).

find... -exec sh -c 'cp "$1" /home/jason/gPodder/mp3' sh {} \;

(вам также не нужно bashтолько для этого. Ваш shподойдет так же ).

Или, что еще лучше, передать сразу несколько аргументов вcp:

find... -exec sh -c 'cp "$@" /home/jason/gPodder/mp3' sh {} +

С помощью GNU cpвы также можете это сделать:

find... -exec cp -t /home/jason/gPodder/mp3 {} +
7
27.01.2020, 20:33

Теги

Похожие вопросы