Копирование файлов на основе списка ввода, специальных символов в именах файлов

Это основано на вопросе здесь .

Проблема :

  • У меня есть TXT-файл со списком имен файлов, которые я хочу скопировать в новую папку папки в оболочке (Mac Terminal)

Подход , где filelist.txt содержит имена файлов (разделенные \ n), которые я хочу скопировать:

# version 1 for file in $(cat filelist.txt); do cp "$file" newfolder; done 

Ошибки:

Если у меня есть имена файлов в filelist.txt, которые содержат тире, пробелы и т. Д., Имена разделяются, и я правильно получаю ошибку No such file .

Вот как я пытаюсь решить эту проблему (добавив к переменной dbl-кавычки):

 # version 2 for file in "$(cat filelist.txt)"; do cp "$file" newfolder; done 

Но это распечатывает все имена файлов (без разделения на пробелы) и ничего не копирует.

Вопросы:

  • Добавление кавычек, как указано выше, решает проблему разделения имен, например, когда я передаю его в echo ; почему это не работает для cp ?

  • Как правильно это сделать с помощью cat и cp ? Комментарий в ответе, связанном выше, предлагает следующее:

    set -f;IFS=$'\n'

который исправляет вещи, но я понятия не имею, что он делает.

Любые намеки очень ценятся!

Есть несколько вариантов; это один:

 cat filelist.txt | while read file; do cp "$file" newfolder done 

Итак, во-первых, почему

 for file in $(cat filelist.txt); do cp "$file" newfolder; done 

не работа? Предположим, что ваш список файлов содержит

 a bc 

$(cat filelist.txt) создает список имен файлов. Цикл for видит выходные данные cat и интерпретирует их как:

 for file in abc ; do 

что явно не намерение.

Вот где помогает замечание о разделителе поля ввода. Обычно IFS является любым пробелом, и поэтому пробел в имени файла будет интерпретироваться как разделение между именами файлов. Если вы явно установите IFS для новой строки, пробел больше не будет рассматриваться как разделитель.

 for file in "$(cat filelist.txt)"; do cp "$file" newfolder; done 

создает единственный аргумент для цикла for. Результат эквивалентен:

 for file in "abc" ; do 

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