Скопіюйте список файлів


35

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

Я намагався зробити:

cp `cat list.txt` new_folder

але це не спрацювало.

Як би ти це зробив?

Оновлення:

Дякую за всі ваші дуже цікаві відповіді. Я не просив стільки :)

Після другого випробування рішення, здається, що cpнадруковано довідку щодо використання, оскільки папка new_folderще не існувала! Вибачте, це здається дурною помилкою ... Коли я створюю папку раніше, вона працює.

Однак я багато чого дізнався з усіх ваших відповідей та рішень, дякую вам за час, який ви витратили на їх написання.


Дозвольте зрозуміти одне: у списку всі назви файлів у одному рядку, розділені лише пробілом? Або імена кожне в окремому рядку?
Телемах

Все в одному вапні, розділеному пробілом. Рішення Дуга спрацювало :) Дякую за відповідь.
Клаус

Це смішно ... Я перевірив своє рішення за допомогою рядка, в якому кожне ім'я було окремим рядком.
Дуг Харріс

"не вийшло" не має великого значення. Точно , як же це не спрацювало. Це прекрасно працює для мене.
Призупинено до подальшого повідомлення.

Вибачте: він показав довідку щодо використання cp. Дивіться моє оновлення вище.
Клаус

Відповіді:


34

Спробуйте використовувати xargs:

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

Оновлення:

Я робив це на ОС 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:)
Клаус,

Це хороша порада використовувати ехо для перевірки своїх команд, перш ніж запускати їх.
Ліам

1
Використовуючи ту саму вище команду з лише необхідними змінами, як я копіюю файли разом із створенням їх каталогів та підкаталів, в яких вони знаходяться, розділених косою рисою?
Вікі Дев

54

Не потрібно catвзагалі:

xargs -a list.txt cp -t new_folder

Або використовуючи довгі варіанти:

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

Ось кілька версій оболонок. Зауважте, що деякі змінні не цитуються або forцикли використовуються спеціально, тому що в ОР визначено, що назви файлів мають пробіл. Деякі з цих методів не працюватимуть для введення імені файлів за рядком, у яких назви файлів містять пробіл.

Bash:

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

або

cp $(<list.txt) new_folder

sh (або Bash):

# 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

noob питання: навіщо це -tпотрібно xargs -a list.txt cp -t new_folder?
Ібо Ян

1
@YiboYang: -tце варіант cp. Він копіює всі вихідні аргументи у вказаний цільовий каталог. Тут він дозволяє вказати ціль перед джерелом, яке додається xargsкомандою.
Призупинено до подальшого повідомлення.

Це корисно, але що робити, якщо list.txt містить змішані файли та шлях папок? У цьому випадку команда не працює належним чином. Він повідомляє "опущення каталогу ...", і якщо -R вказано команді cp, тоді помилка "не є каталогом" повідомляється, як тільки виникає перший файл у списку.
Беміпефе

7

Раніше тут я мав бентежну відповідь, але відповідь Дениса нагадала мені, що я пропустив найосновніше. Отже, я видалив свою оригінальну відповідь. Але оскільки ніхто не сказав цього дуже елементарного, я вважаю, що варто це поставити тут.

Оригінальне запитання - "У мене є текстовий файл із переліком розділених пробілами імен файлів. Як їх скопіювати в один цільовий каталог". Спочатку це може здатися хитромудрим або складним, оскільки ви думаєте, що вам потрібно якось певним чином витягти елементи з файлу. Однак, коли оболонка обробляє командний рядок, перше, що вона робить, - це розділити список аргументів на маркери і (ось біт, який ніхто не сказав прямо), пробіли окремі лексеми . (Newlines також окремі лексеми, тому тест Дуга Харріса з новим розділеним списком мав той же результат.) Тобто оболонка очікує і вже може обробляти список, розділений пробілом.

Отже, все, що вам потрібно зробити тут, - поставити розділений пробілом список (який у вас уже є) на потрібне місце у вашій команді. Ваша команда щодо цього є різною:

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

$()змушує оболонку запускати команду всередині круглих дужок, а потім підміняти її вихід у цій точці у більшому рядку. Потім оболонка запускає лінію в цілому. До речі, $()це більш сучасна версія того, що ви вже робили з backticks (`). Далі: <оператор перенаправлення файлів. Він повідомляє оболонці скинути вміст 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

@dhaupin Власне, ОП заявляє, що він був на macOS. Тож для чого це варто, --parentsпрапор там не існує. Їх (похідна від BSD) версія cpнадає лише короткі варіанти, а не довгі варіанти у стилі GNU. Для стилю BSD cpпрапор рекурсивної копії - це великі -R, а не малі.
Телемах
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.