Создание сценария BASH " для " обрабатывать имена файлов с пробелами (или обходной путь)

хотя я использую BASH уже несколько лет, мой опыт работы с bash scripting относительно ограничен.

мой код, как показано ниже. Он должен захватить всю структуру каталогов из текущего каталога и реплицировать ее в $OUTDIR.

for DIR in `find . -type d -printf ""%P"0"`
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"0"`

и вывод с этой измененной строкой:

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 на каждом файле в следующей аналогичной структуре. Как должен ли я этим заниматься?

Edit: мне нужна структура кода, которая позволит мне запускать несколько строк кода для каждого каталога/файла/цикла. Извините, если я неясно выразился.

устранение: я изначально пробовал:

find . -type d | while read DIR
do
  mkdir -p "${OUTPATH}${DIR}"
  echo Created $DIR
done

это работало отлично по большей части. Однако позже я обнаружил, что, поскольку труба приводит к циклу while, работающему в подэлементе, любые переменные, установленные в цикле, позже были недоступны, что сделало реализацию счетчик ошибок довольно сложный. Мое окончательное решение (от это ответ на так):

while read DIR
do
  mkdir -p "${OUTPATH}${DIR}"
  echo Created $DIR
done < <(find . -type d)

это позже позволило мне условно инкрементировать переменные в цикле, которые останутся доступными позже в сценарии.

17
задан Community
29.04.2023 12:16 Количество просмотров материала 2976
Распечатать страницу

8 ответов

вам нужно трубы find на while петли.

find ... | while read -r dir
do
    something with "$dir"
done

кроме того, вам не нужно использовать -printf в этом случае.

вы можете сделать это доказательство против файлов с новыми строками в их именах, если хотите, используя разделитель nullbyte (это единственный символ, который не может появиться в *nix filepath):

find ... -print0 | while read -d '' -r dir
do
    something with "$dir"
done

вы найдете с помощью $() вместо backticks, котор нужно быть разносторонне и легке. Они могут быть вложены гораздо легче и цитировать можно сделать очень более легко. Этот пример иллюстрирует следующие моменты:

echo "$(echo "$(echo "hello")")"

попробуйте сделать это с помощью backticks.

11
отвечен Dennis Williamson 2023-04-30 20:04

See ответ я писал несколько дней назад пример скрипта, который обрабатывает имена файлов с пробелами.

есть немного более запутанный (но более краткий) способ добиться того, что вы пытаетесь сделать:

find . -type d -print0 | xargs -0 -I {} mkdir -p ../theredir/{}

-print0 говорит find отделять аргументы null; -0 к xargs говорит ему ожидать аргументы, разделенные null. Это значит что оно регулирует космосы отлично.

-I {} говорит xargs заменить строку {} С именем. Это также означает, что в командной строке должно использоваться только одно имя файла (xargs обычно заполняет столько, сколько поместится в строке)

остальное должно быть очевидно.

7
отвечен James Polley 2023-04-30 22:21

проблема, с которой вы столкнулись, заключается в том, что оператор for отвечает на поиск как отдельные аргументы. Разделитель пробелов. Вам нужно использовать переменную IFS bash, чтобы не разделять пространство.

здесь ссылке это объясняет как это делать.

внутренняя переменная IFS

один из способов обойти эту проблему-изменить внутреннюю переменную IFS Bash (внутренний разделитель полей), чтобы она разделяла поля чем-то другим, кроме пробелы по умолчанию (пробел, табуляция, перевод строки), в данном случае запятая.

#!/bin/bash
IFS=$';'

for I in `find -type d -printf \"%P\"\;`
do
   echo "== $I =="
done

установите find для вывода разделителя полей после %P и установите IFS соответствующим образом. Я выбрал точку с запятой, так как это вряд ли можно найти в ваших именах файлов.

другой альтернативой является вызов mkdir из поиска непосредственно через -exec вы можете пропустить цикл for вообще. Это если вам не нужно делать дополнительный парсинг.

5
отвечен Darren Hall 2023-05-01 00:38

Если тело цикла больше, чем одна команда, можно использовать xargs вбить скрипт:

export OUTPATH=/some/where/else/
find . -type d -print0 | xargs -0 bash -c 'for DIR in "$@"; do
  printf "mkdir -p %q\n" "${OUTPATH}${DIR}"        # Using echo for debug; working script will simply execute mkdir
  echo Created $DIR
done' -

Не забудьте включить конечную черточку (или какое-либо другое "слово"), если оболочка имеет разновидность Bourne/POSIX (она используется для установки $0 в сценарии оболочки). Кроме того, необходимо соблюдать осторожность с кавычками, так как сценарий оболочки записывается внутри заключенной в кавычки строки, а не непосредственно в приглашении.

4
отвечен Chris Johnsen 2023-05-01 02:55

в обновленном вопросе у вас есть

mkdir -p \"${OUTPATH}${DIR}\"

это должно быть

mkdir -p "${OUTPATH}${DIR}"
1
отвечен user23307 2023-05-01 05:12
find . -type d -exec mkdir -p "{}0" ';' -exec echo "Created {}0" ';'
1
отвечен Vouze 2023-05-01 07:29

или сделать все намного проще:

% rsync -av --include='*/' --exclude='*' SRC DST

это реплицирует структуру каталогов SRC в DST.

0
отвечен akira 2023-05-01 09:46

Если у вас GNU Parallel http:// www.gnu.org/software/parallel / installed вы можете сделать это:

find . -type d | parallel echo making {} ";" mkdir -p /tmp/outdir/{} ";" echo made {}

посмотрите вступительное видео для GNU Parallel, чтобы узнать больше: http://www.youtube.com/watch?v=OpaiGYxkSuQ

0
отвечен Ole Tange 2023-05-01 12:03

Постоянная ссылка на данную страницу: [ Скопировать ссылку | Сгенерировать QR-код ]

Ваш ответ

Опубликуйте как Гость или авторизуйтесь

Имя
Вверх