Как скопировать или переместить файлы -n уровня вверх на OSX через оболочку

381
Alex Starbuck

Как я могу найти все файлы определенного типа / имени и скопировать их на уровень выше ? Вот древовидная структура файловой системы:

germany/ | adventure/ | 300x600/ | | | file1.jpg | file2.zip | 400x600/ | file8.jpg file4.zip switzerland/ | adventure/... 

Существует много страновых папок, около 20, и файлы .zip не гарантированно имеют 3 уровня глубины. В настоящее время я нахожусь в их родительской папке, countries/и я хочу найти и скопировать все файлы .zip на один уровень выше, в adventure/каталог соответствующей страны / папки.

Я старался:

find . -type f -name '*.zip' -exec mv {}/.. \; 

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

Спасибо!

РЕДАКТИРОВАТЬ: Я немного поиграл с решениями из ответов и прочитал много manстраниц :). Наконец, я принял решение, которое мне понравилось больше всего, так как оно элегантное и не зависит от оболочки.

Что-то я все еще пытаюсь выяснить:

  1. Работает ли findкак цикл или фигурные скобки считаются списком / массивом в других языках программирования? Значение: он заполняется найденными результатами (т. Е. Строками) одновременно и ТО передается команде под -exec?
  2. Почему движение сначала произошло на один уровень вверх, а затем снова на один уровень вверх?
  3. Есть ли способ, чтобы сразу сказать mv/cpперейти на -n уровней [вверх / вниз]?
2

3 ответа на вопрос

0
Phillip -Zyan K Lee- Stockmann

попробовал это с ubuntu zsh 5.0.2:

for pdir in */ do cd $pdir for dir in */ do cd $dir mv */*.zip . cd .. done cd .. done 
Близко. Я хочу, чтобы все файлы .zip были на два уровня выше, то есть в подкаталоге `adventure /` каталога `germany /`. Кроме того, существуют другие каталоги, названные по именам стран, поэтому я хотел бы иметь возможность выдать команду для всех этих (например, Австрия /, Германия /, ...). Спасибо Alex Starbuck 8 лет назад 0
хорошо - позвольте мне попробовать еще раз - но опять же, нет zsh, чтобы проверить это ;-) Phillip -Zyan K Lee- Stockmann 8 лет назад 0
Я попробовал это в контейнере Ubuntu LXC и с Zsh 5.0.2. Должен работать как шарм ;-) Phillip -Zyan K Lee- Stockmann 8 лет назад 0
Это должно работать, но только для одного каталога на корневом уровне (например, `germany`), но не для всех. slhck 8 лет назад 0
Как насчет сейчас? :-D Phillip -Zyan K Lee- Stockmann 8 лет назад 0
0
slhck

Вы можете сделать его независимым от оболочки и объединить его в одну findкоманду:

find . -type f -name '*.zip' -exec \ sh -c 'echo cp -- "$0" "$(dirname "$0")"/..' {} \; 

Удалите, echoкогда вы уверены, что он делает то, что вы хотите.

Используйте, findчтобы найти файлы. Запустите оболочку с -exec sh -c, передав найденный файл {}в качестве первого аргумента этой оболочке. Поэтому в оболочке путь к файлу будет доступен как $0.

Затем вы можете использовать dirname "$0"и команду substitution ( $(…)) для получения родительского каталога файла. Добавить столько, /..сколько вы хотите пройти выше.

Обратите внимание, что я цитировал имена файлов, чтобы предотвратить неправильное расширение файлов с символами новой строки или пробелами в их имени.

Примечание: в своем вопросе вы говорите, что хотите «скопировать», но позже вы используете команду `mv`. Я предполагал, что вы хотите скопировать файлы, как говорится в заголовке и введении. slhck 8 лет назад 0
Понял! `mv`or` cp` не имеет значения, я могу использовать и обрабатывать оба :). Итак, `find` находит пути к файлам .zip, заполняет" {} `" объект "результатами. `-exec` выполняет` sh -c` с опцией "read from string" (-c), которая "определяет" (?) два аргумента - первый аргумент будет первым `path / to / file.zip` из результатов` { } `. Затем, extract-parent-dir-of-the-file, наконец поднимитесь на один уровень вверх и файл `cp`. Правильный? Alex Starbuck 8 лет назад 0
Да, это в значительной степени то, что здесь происходит! В этом случае у вызова `sh` есть два аргумента: один -` -c "cmd" `(=« взять команды, которые должны быть выполнены из строки, которая следует »), а второй -` {} `, то есть - как вы правильно сказали - путь до первого найденного файла, затем во втором цикле второй файл и т. Д. Этот подход `-exec sh -c"… "` довольно полезен для более сложных сценариев `find`, которые вы ' иначе пришлось бы написать несколько петель для. slhck 8 лет назад 0
Не могли бы вы уточнить еще немного - я запутался в связи со строкой. Существует команда (cp), за которой следуют две переменные ($ 0 и $ (...)). Как это работает внутри? Как полный путь / к / файлу заканчивается в $ 0 и чем к этому применяется другая команда dirname? Vielen Dank! Alex Starbuck 8 лет назад 0
`$ 0` - это первый аргумент, переданный в` sh -c '…' `. Вы можете запустить `sh -c 'echo $ 0 $ 1 $ 2' foo bar baz` и вы получите` foo bar baz` в качестве вывода. В вашем случае первым аргументом был `{}`, который `find` заменяет на путь к найденному файлу. Таким образом, первым аргументом `cp` является путь к файлу. Второй аргумент должен быть родительской папкой файла, поэтому нам нужно сначала получить имя папки… slhck 8 лет назад 0
Для этого выполняется команда `dirname" $ ​​0 "`. Его вывод - это, очевидно, просто каталог файла. Вывод команды буквально помещается туда, куда идет второй аргумент `cp` - это называется подстановка команды (см. Ссылку выше). Подстановка команды выполняется * до * оценки остальной части строки. Это очень полезно, если вы хотите, чтобы ваша команда оболочки содержала вывод другой команды. Таким образом, `$ (dirname" $ ​​0 ")` в конечном итоге становится `/ path / to / folder` в последней команде, к которой мы просто добавляем` / .. `для получения родительской папки. slhck 8 лет назад 0
Понял! Просто синтаксис мне кажется странным. Find, затем options, затем sh, затем аргумент для sh и в конце снова то, что «работает» с find (фигурные скобки). Я думаю, это просто что-то. запомнить;) Alex Starbuck 8 лет назад 0
0
Matija Nalis

Просто быстрая альтернатива, если реальность так проста, как приведенный пример:

cd germany mv */*/*.zip . 

(и там не миллионы файлов)

Как упомянуто в комментарии выше, OP хочет сделать это для * каждой * папки, а не только для «Германии». Так что вам понадобится цикл по всем папкам. slhck 8 лет назад 0
Да, я должен сделать это для всех папок "страны", а не только для одной, и я не уверен, что файлы .zip всегда будут иметь три уровня глубины. Спасибо, в любом случае ;) Alex Starbuck 8 лет назад 0