Хотя я использую BASH в течение нескольких лет, мой опыт работы со сценариями BASH относительно ограничен.
Мой код, как показано ниже. Он должен получить всю структуру каталогов из текущего каталога и скопировать его в $OUTDIR
.
for DIR in `find . -type d -printf "\"%P\"\040"`
do
echo mkdir -p \"${OUTPATH}${DIR}\" # Using echo for debug; working script will simply execute mkdir
echo Created $DIR
done
Проблема, вот пример моей файловой структуры:
$ ls
Expect The Impossible-Stellar Kart
Five Iron Frenzy - Cheeses...
Five Score and Seven Years Ago-Relient K
Hello-After Edmund
I Will Go-Starfield
Learning to Breathe-Switchfoot
MMHMM-Relient K
Обратите внимание на пробелы: -S И for
принимает параметры слово за словом, поэтому вывод моего скрипта выглядит примерно так:
Creating directory structure...
mkdir -p "/myfiles/multimedia/samjmusicmp3test/Learning"
Created Learning
mkdir -p "/myfiles/multimedia/samjmusicmp3test/to"
Created to
mkdir -p "/myfiles/multimedia/samjmusicmp3test/Breathe-Switchfoot"
Created Breathe-Switchfoot
Но мне нужно, чтобы получить целые имена файлов (по одной строке за раз) из вывода find
. Я также попытался сделать find
двойные кавычки вокруг каждого имени файла. Но это не помогает.
for DIR in `find . -type d -printf "\"%P\"\040"`
И вывод с этой измененной строкой:
Creating directory structure...
mkdir -p "/myfiles/multimedia/samjmusicmp3test/"""
Created ""
mkdir -p "/myfiles/multimedia/samjmusicmp3test/"Learning"
Created "Learning
mkdir -p "/myfiles/multimedia/samjmusicmp3test/to"
Created to
mkdir -p "/myfiles/multimedia/samjmusicmp3test/Breathe-Switchfoot""
Created Breathe-Switchfoot"
Теперь мне нужен какой-то способ, с помощью которого я могу выполнять итерации, как это, потому что я также хочу выполнить более сложную команду, включающую gstreamer
в каждый файл следующую аналогичную структуру. Как я должен это делать?
Редактировать: мне нужна структура кода, которая позволит мне запускать несколько строк кода для каждого каталога / файла / цикла. Извините, если мне было неясно.
Решение: я изначально попробовал:
find . -type d | while read DIR
do
mkdir -p "${OUTPATH}${DIR}"
echo Created $DIR
done
Это работало нормально по большей части. Однако позже я обнаружил, что, поскольку конвейер приводит к выполнению цикла while в подоболочке, все переменные, установленные в цикле, впоследствии были недоступны, что затрудняло реализацию счетчика ошибок. Мое окончательное решение (из этого ответа на SO ):
while read DIR
do
mkdir -p "${OUTPATH}${DIR}"
echo Created $DIR
done < <(find . -type d)
Позже это позволило мне условно увеличивать переменные в цикле, которые позже будут доступны в скрипте.
/
и непечатаемых символов. Но разрешено все, кроме вас,/
и\0
вы должны их разрешить.Ответы:
Тебе нужно пускать
find
вwhile
петлю.Кроме того, вам не нужно использовать
-printf
в этом случае.Вы можете сделать это доказательство для файлов с символами новой строки в их именах, если хотите, используя разделитель нулевым байтом (это единственный символ, который не может появиться в * nix filepath):
Вы также найдете использование
$()
вместо обратных кавычек более универсальным и простым. Они могут быть вложены гораздо проще, а цитирование - гораздо проще. Этот надуманный пример проиллюстрирует эти моменты:Попробуйте сделать это с помощью обратных кавычек.
источник
"$dir"
него предпочтительнее использовать"${dir}"
- легко определить разницу между $ {dir} name и $ {dirname}, но $ dirname можно интерпретировать в любом случае.read
вся строка читается${dir}
, поэтому IFS не имеет значения.find … -print0 | xargs -0 …
потому что используемый разделитель точно соответствует единственному символу, который не разрешен в названиях путей POSIX: NUL (U + 0000).while
. @Chris Johnsen: Да, но даже программы для копирования музыки не склонны вставлять переводы строк в свои имена файлов. И если они это сделают, я хочу знать (то есть: что-то идет не так) и немедленно избавиться от них ...Посмотрите этот ответ, который я написал несколько дней назад, для примера скрипта, который обрабатывает имена файлов с пробелами.
Есть немного более запутанный (но более лаконичный) способ достичь того, что вы пытаетесь сделать:
-print0
говорит find для разделения аргументов с нулем; от -0 до xargs говорит ему ожидать аргументы, разделенные нулями. Это означает, что он прекрасно обрабатывает пробелы.-I {}
говорит xargs заменить строку{}
именем файла. Это также подразумевает, что в командной строке должно использоваться только одно имя файла (обычно xargs будет заполнять столько, сколько поместится в строке)В остальном должно быть очевидно.
источник
Проблема, с которой вы сталкиваетесь, заключается в том, что оператор for отвечает на поиск как отдельные аргументы. Разделитель пространства. Вам нужно использовать переменную IFS bash, чтобы не разделять пространство.
Вот ссылка, которая объясняет, как это сделать.
Настройте свою находку для вывода разделителя полей после% P и установите свой IFS соответствующим образом. Я выбрал точку с запятой, так как это вряд ли можно найти в ваших именах файлов.
Другой альтернативой является вызов mkdir из поиска напрямую через
-exec
, если вы можете вообще пропустить цикл for. Это если вам не нужно делать дополнительный анализ.источник
/
на POSIX, так и:
на файловых системах DOS. Существуют недопустимые символы для разных файловых систем, которые вы можете выбрать для IFS. Что-нибудь более сложное, и вам лучше использовать Perl.find
возвращает имена файлов с путями, включая косую черту. Попробуйте изменить точку с запятой в вашем скрипте на косую черту, и echo напечатает каталог и имя файла в отдельных строках.while
варианту, но это также выглядит вполне работоспособным. Да, в моей аналогичной структуре позже мне нужно было сделать дальнейший анализ. (Входное имя файла будет .ogg, которое будет передано какfilesrc
в конвейере gst, но будет сгенерировано эквивалентное окончание .mp3 на основе выходного каталога, а также передано в конвейер какfilesink
, и это, конечно, необходимо сделать для каждого файла вместе с некоторымиecho
для пользователя.)Если тело вашего цикла больше чем одна команда, можно использовать xargs для запуска сценария оболочки:
Не забудьте включить завершающую черту (или другое слово), если оболочка относится к разновидности Bourne / POSIX (она используется для установки $ 0 в сценарии оболочки). Кроме того, следует соблюдать осторожность при заключении в кавычки, поскольку сценарий оболочки пишется внутри строки в кавычках, а не непосредственно в приглашении.
источник
в вашем обновленном вопросе у вас есть
это должно быть
источник
источник
или сделать все это намного менее сложным:
это копирует структуру каталогов SRC в DST.
источник
while
...do
...done
структуру, чтобы выполнить аналогичную обработку из find, что потребует выполнения нескольких строк кода для каждого файла (изменение строки, echo, gst-launch и т. Д. ) иrsync
не достиг бы этого. Вот почему я указал, что мне нужно иметь возможность запускать более сложный набор команд в рамках аналогичной структуры. Мой сценарий использует эту структуру цикла дважды, поэтому для вопроса я разместил в середине тот, который был менее грубым.Если у вас установлен GNU Parallel http: // www.gnu.org/software/parallel/, вы можете сделать это:
Посмотрите вступительное видео для GNU Parallel, чтобы узнать больше: http://www.youtube.com/watch?v=OpaiGYxkSuQ
источник