Скопировать список файлов

35

У меня есть список файлов, разделенных пробелами в файле list.txt. Я хотел бы скопировать их в новую папку.

Я пытался сделать:

cp `cat list.txt` new_folder

но это не сработало.

Как бы вы это сделали?

Обновить:

Спасибо за все ваши очень интересные ответы. Я не так много просил :)

После того, как вы попробовали решение выше во второй раз, кажется, что cpнапечатали справку по использованию, потому что папка new_folderеще не существовала! Извините, это кажется глупой ошибкой ... Когда я создаю папку раньше, она работает.

Тем не менее, я многому научился из всех ваших ответов и решений, спасибо за то, что вы потратили время на их написание.

Клаус
источник
Позвольте мне прояснить одну вещь: список содержит все имена файлов в одной строке, разделенные только пробелом? Или имена каждого в отдельной строке?
Телемах
Все в одной извести, разделенных пробелом. Решение Дуга сработало :) Спасибо за ответ.
Клаус
Забавно ... Я проверил свое решение с помощью строки, в которой каждое имя было на отдельной строке.
Даг Харрис
«это не сработало» не очень значимо. Точно, как это не работает. Он отлично работает для меня.
Приостановлено до дальнейшего уведомления.
Извините: он показал справку по использованию cp. Смотрите мое обновление выше.
Клаус

Ответы:

34

Попробуйте использовать xargs:

cat list.txt | xargs -J % cp % new_folder

Обновить:

Я сделал это на OS X, версия которого отличается от версии GNU / Linux. То, xargsчто исходит от GNU findutils , не имеет, -Jно имеет -Iаналогичное (как отметил Деннис Уильямсон в комментарии). Версия Xargs для OS X имеет и то, -Iи другое и -Jнемного отличается по поведению - либо подойдет для этого оригинального вопроса.

$ cat list.txt
one
two.txt
three.rtf

$ cat list.txt | xargs -J % echo cp % new_folder
cp one two.txt three.rtf new_folder

$ cat list.txt | xargs -I % echo cp % new_folder
cp one new_folder
cp two.txt new_folder
cp three.rtf new_folder
Даг Харрис
источник
3
У меня xargsнет -Jэтого, -Iкоторый, кажется, делает то же самое. Какая версия xargsи какая у вас ОС / дистрибутив?
Приостановлено до дальнейшего уведомления.
Я проверил это на Mac OS X 10.6 (он же снежный барс), так что это любая версия xargs, поставляемая с ОС. Запуск xargs --versionвозвращает сообщение об ошибке использования. Это скорее всего BSD-версия xargs. Использование -Iи -Jтонко отличаются. Я обновлю свой ответ с хорошо отформатированными примерами.
Даг Харрис
Да, я работаю с Mac OSX 10.6. Спасибо за точность о -Jи -I:)
Клаус
Это хороший совет, чтобы использовать echo для проверки ваших команд перед их выполнением.
Лиам
1
Используя ту же команду, приведенную выше, только с необходимыми изменениями, как мне скопировать файлы вместе с созданием их каталогов и подкаталогов, в которых они находятся, разделенных косой чертой?
Вики Дев
54

Нет необходимости catвообще:

xargs -a list.txt cp -t new_folder

Или используя длинные опции:

xargs --arg-file=list.txt cp --target-directory=new_folder

Вот несколько версий оболочки. Обратите внимание, что некоторые переменные не заключены в кавычки или forциклы используются специально, потому что OP указал, что имена файлов разделены пробелом. Некоторые из этих методов не будут работать для ввода имени файла на строку, в котором имена файлов содержат пробелы.

Bash:

for file in $(<list.txt); do cp "$file" new_folder; done

или

cp $(<list.txt) new_folder

ш (или Баш):

# still no cat!
while read -r line; do for file in $line; do cp "$file" new_folder; done; done < list.txt

или

# none here either
while read -r line; do cp $line new_folder; done < list.txt

или

# meow
for file in $(cat list.txt); do cp "$file" new_folder; done

или

# meow
cp $(cat list.txt) new_folder
Приостановлено до дальнейшего уведомления.
источник
нуб вопрос: зачем -tнужен xargs -a list.txt cp -t new_folder?
Ибо Ян
1
@YiboYang: -tэто вариант cp. Он копирует все исходные аргументы в указанный целевой каталог. Здесь он позволяет указать цель перед источником, добавляемым xargsкомандой.
Приостановлено до дальнейшего уведомления.
Это полезно, но что, если list.txt содержит путь к смешанным файлам и папкам? В этом случае команда не работает должным образом. Он сообщает «Пропуск каталога ...», и если в команде cp указано -R, то об ошибке «не каталог» сообщается, как только встречается первый файл в списке.
Bemipefe
7

Раньше у меня был смущающий круговой ответ здесь, но ответ Дениса напомнил мне, что я пропустил самую основную вещь. Итак, я удалил свой оригинальный ответ. Но так как никто не сказал эту самую основную вещь, я думаю, что это стоит поместить здесь.

Исходный вопрос: «У меня есть текстовый файл со списком разделенных пробелами имен файлов. Как я могу скопировать их в один целевой каталог». Сначала это может показаться сложным или сложным, потому что вы думаете, что вам нужно каким-то образом извлечь элементы из файла определенным образом. Тем не менее, когда оболочка обрабатывает командную строку, первое, что она делает, - разделяет список аргументов на токены и (это бит, который никто не сказал прямо) пробелами отдельные токены . (Новые строки также разделяют токены, поэтому тест Дуга Харриса со списком, разделенным новой строкой, дал тот же результат.) То есть оболочка ожидает и уже может обрабатывать разделенный пробелами список.

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

cp file1 file2 file3...file# target

Единственная проблема заключается в том, что вы хотите получить список файлов с 1 по # из вашего текстового файла.

Как отмечает Деннис в своем комментарии, ваша первоначальная попытка ( cpcat list.txt new_folder) уже сработала Зачем? Поскольку внутренняя команда cat list.txtсначала обрабатывается оболочкой и расширяется в нее file1 file2 file3...file#, это именно то, что оболочка ожидает и хочет в этой части команды. Если это не сработало, либо (1) у вас была опечатка, либо (2) ваши имена файлов были как-то странными (в них были пробелы или другие необычные символы).

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

cp list-of-files target_directory

Легко увидеть, как все это объединяется в этой версии:

cp $(<list.txt) new_folder

$()заставляет оболочку запускать команду в круглых скобках, а затем подставлять ее вывод в эту точку в большей строке. Затем оболочка запускает линию в целом. Кстати, $()это более современная версия того, что вы уже делали с обратными галочками (`). Далее: <оператор перенаправления файлов. Он говорит оболочке вывести содержимое list.txtв стандартный ввод. Поскольку $()бит обрабатывается первым, вот что происходит поэтапно:

  1. cp $(<list.txt) new_folder # split line into three tokens: cp, $(<list.txt), new_folder
  2. cp file1 file2 file3...file# new_folder # substitute result of $(<list.txt) into the larger command

Очевидно, шаг 2 - просто нормальная cpкоманда, которую вы хотели.

Я понимаю, что много бью эту (возможно, очень мертвую) лошадь, но думаю, это стоит того. Понимание того , как оболочка обрабатывает команду, может помочь вам написать ее лучше и значительно упростить. Это также покажет вам, где проблемы могут скрываться. В этом случае, например, мой первый вопрос к вам должен был быть о забавных именах файлов или возможной опечатке. Никакой акробатики не было необходимости.

Телемах
источник
@Klaus Не за что. Честно говоря, я был в основном раздражен собой после того, как прочитал ответ Денниса и понял, что полностью пропустил ключевую часть проблемы. Решение, которое вам нравится, тоже оттуда.
Телемах
Это очень старый ответ, но если вам нужно заново создать структуру папок, вам нужен --parentsфлаг. Вы можете сделать это многословным -vдля записи того, что было скопировано. Если вы хотите сохранить права доступа, вам нужен флаг -aили -p. Т.е., cp --parents -av $(<list.txt) new_folder. Все это при условии, что ваш список файлов действительно является всеми файлами, в противном случае вам также может понадобиться -rфлаг для рекурсии.
дхаупин
@dhaupin На самом деле ОП утверждает, что он был на macOS. Так что, чего бы это ни стоило, --parentsфлага там не существует. Их (производная от BSD) версия предоставляет cpтолько короткие опции, а не длинные опции в стиле GNU. Для стиля BSD cpфлаг для рекурсивного копирования - прописные -R, а не строчные.
Телемах