Bash: копіюйте названі файли рекурсивно, зберігаючи структуру папок


103

Я сподівався:

cp -R src/prog.js images/icon.jpg /tmp/package

отримав би симетричну структуру в режимі призначення:

/tmp
|
+-- package
    |
    +-- src
    |   |
    |   +-- prog.js
    |
    +-- images
        |
        +-- icon.jpg

але натомість обидва файли копіюються в / tmp / package. Плоска копія. (Це на OSX).

Чи є проста функція bash, яку я можу використовувати, щоб скопіювати всі файли, включаючи файли, визначені символом wildcard (наприклад, src / *. Js), на належне місце в каталозі призначення. Трохи на кшталт "для кожного файлу, запустіть mkdir -p $(dirname "$file"); cp "$file" $(dirname "$file")", але, можливо, одна команда.

Це відповідна нитка, яка дозволяє припустити, що це неможливо. Авторське рішення не дуже корисне для мене, тому що я хотів би просто надати список файлів, підстановку чи ні, і всі вони скопійовані до місця призначення. IIRC MS-DOS xcopy робить це, але, схоже, немає еквівалента для cp.

Відповіді:


153

Ви спробували скористатися опцією --parents? Я не знаю, чи підтримує OS X, але це працює в Linux.

cp --parents src/prog.js images/icon.jpg /tmp/package

Якщо це не працює в OS X, спробуйте

rsync -R src/prog.js images/icon.jpg /tmp/package

як запропонував Aif.


4
Дякую. виявляється "cp --parents" неможливо на mac, але приємно знати прапор для інших unixen. rsync -R є найпростішим портативним рішенням цієї проблеми.
mahemoff

1
Я прийняв цей за його елегантність / запам'ятовуваність, але щойно виявив, що він не копіює цілі каталоги (принаймні на OSX), тоді як той, що знаходиться нижче, - це.
mahemoff

cp --parentsє незаконним варіантом в OSX (BSD cp), але gcp(GNU cp) працює чудово. Якщо його ще немає у вашій системі, користуйтеся brew install coreutils. У вас буде багато утиліт з префіксом g.
kyb

@mahemoff cp -R --parentsі rsync -rRкопії обох файлів і каталогів , порівняно.
Vortico

22

Односторонній:

tar cf - <files> | (cd /dest; tar xf -)

о, мені це подобається набагато краще, ніж моя відповідь.
EMPraptor

4
Ви також можете скористатися -Cопцією, щоб зробити chdir для вас - tar cf - _files_ | tar -C /dest xf -або щось подібне.
Д.Шоулі

дякую, це стисло, хоча я віддаю перевагу rsync для простоти.
mahemoff

1
Чудово! Хтось знає, як перетворити це на команду оболонки? Він повинен приймати N входів, перший N-1 - це файли, які потрібно скопіювати, а останній - папка призначення.
арод

@arod $ {! #} є останньою парам і використовуйте це для отримання попередніх аргументів stackoverflow.com/questions/1215538/… . Якщо ви пишете команду, будь ласка, посилайтесь на суть тут.
mahemoff

18

Крім того, якщо ви старенька школа, використовуйте cpio:

cd /source;
find . -print | cpio -pvdmB /target

Зрозуміло, ви можете відфільтрувати список файлів до вмісту серця.

Параметр '-p' призначений для режиму "проходження" (проти "-i" для введення або "-o" для виведення). '-V' є багатослівним (список файлів під час їх обробки). '-M' зберігає час модифікації. '-B' означає використовувати "великі блоки" (де великі блоки - 5120 байт замість 512 байт); можливо, це не має ефекту в ці дні.


1
Краще використовувати -print0комбінацію --nullопцій, щоб вона не розірвалась із спеціальними символами та такими:find . -print0 | cpio -pvdmB --null /target
haridsv

Назвіть це old-school, називайте його портативним, називайте його будь-яким, але я точно довіряю cpioцьому завданню. Я погоджуюсь, що -print0і -nullпараметри слід використовувати, інакше в якийсь момент хтось видасть вам папки з "спеціальними символами" (пробіли, швидше за все), і щось станеться. Не те, що я кажу з особистого досвіду, але ви можете спробувати створити резервну копію файлів і лише в кінці половини з них створити резервну копію через пробіли у назви файлів. (Гаразд, я кажу з особистого досвіду.)
bballdave025

@ bballdave025: Ви стикаєтеся лише з проблемами, cpioяк показано, якщо файли містять нові рядки - тоді ви, як правило, отримуєте повідомлення про помилку про те, що два (або більше) імена файлів не знайдено для кожного нового рядка у назві файлу. (Іноді ви можете отримати менше повідомлень, але це вимагає значної обережності при складанні тестового випадку.) Коли я використовував cpio, не було --nullможливості; Параметри подвійного тире не були частиною нотацій варіантів SVR4, і концепція -print0не була присутня findні в одному. Але це вже давно (наприклад, середина 90-х. До того, як Linux досяг домінування).
Джонатан Леффлер

Дякую за деталі, @Jonathan_Leffler. Я люблю тут навчатися. Тепер я намагаюся згадати, яку я зробив помилку рекурсивної копії, яка створила мені проблеми з пробілами - є багато способів, які я міг би зробити цю помилку,
bballdave025

@ bballdave025 - Одна можливість використання xargsв суміші - вона розбивається на пробіл - пробіли, вкладки, нові рядки. ОТОХ, я не впевнений, як і чому ти зробив би це. У cpioманіпуляції GNU у вихідному режимі чітко про одне ім'я файлу на рядок. Посібник користувача SVR4 (надрукований 1990 р.) Невиразний: cpio -o(режим копіювання) зчитує стандартний вхід для отримання списку імен шляхів та копіювання цих файлів на стандартний вихід разом із назвою шляху та інформацією про стан. Тому є ймовірність, що він зламав імена на пробілах.
Джонатан Леффлер

16

rsync -R варіант виконає те, що ви очікуєте. Це дуже багатий на функції копіювач файлів. Наприклад:

$ rsync -Rv src/prog.js images/icon.jpg /tmp/package/
images/
images/icon.jpg
src/
src/prog.js

sent 197 bytes  received 76 bytes  546.00 bytes/sec
total size is 0  speedup is 0.00

Приклад результатів:

$ find /tmp/package
/tmp/package
/tmp/package/images
/tmp/package/images/icon.jpg
/tmp/package/src
/tmp/package/src/prog.js


1

Спробуйте ...

for f in src/*.js; do cp $f /tmp/package/$f; done

тож для того, що ви робили спочатку ...

for f in `echo "src/prog.js images/icon.jpg"`; do cp $f /tmp/package/$f; done

або

v="src/prog.js images/icon.jpg"; for f in $v; do cp $f /tmp/package/$f; done

Вам не потрібно echoабо $vтут. Також цей спосіб не вдасться, якщо відповідного каталогу не існує в пункті призначення.
Вейджун Чжоу
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.