У меня есть структура каталогов, которая выглядит так:

main_directory/
    directory1:
        sub_directory1:
            files:
                myfile.txt
                otherfile.txt
        sub_directory2:
            files:
                myfile.txt
                otherfile.txt
        sub_directory3:
            files:
                myfile.txt
                otherfile.txt
        sub_directory4:
            files:
                myfile.txt
                otherfile.txt
    directory2:
        sub_directory1:
            files:
                myfile.txt
                otherfile.txt
        sub_directory2:
            files:
                myfile.txt
                otherfile.txt
        sub_directory3:
            files:
                myfile.txt
                otherfile.txt
        sub_directory4:
            files:
                myfile.txt
                otherfile.txt

Я пытаюсь выяснить (методом проб и ошибок, потому что я не эксперт в Linux), как сжимать только файлы myfile.txt во всех каталогах. Поскольку все они имеют одно и то же имя файла и разные пути (обойти это было невозможно), мне также нужно сохранить путь к файлам в архиве. Итак, окончательный архивный файл tar, который я хочу создать, будет иметь следующее содержимое:

mytar.tar.gz
    main_directory/directory1/sub_directory1/files/myfile.txt
    main_directory/directory1/sub_directory2/files/myfile.txt
    main_directory/directory1/sub_directory3/files/myfile.txt
    main_directory/directory1/sub_directory4/files/myfile.txt
    main_directory/directory2/sub_directory1/files/myfile.txt
    main_directory/directory3/sub_directory2/files/myfile.txt
    main_directory/directory4/sub_directory3/files/myfile.txt
    main_directory/directory5/sub_directory4/files/myfile.txt

Есть ли простой способ bash сделать это? Полагаю, я мог бы написать для этого сценарий python, но это кажется излишним.

Есть ли у кого-нибудь совет?

4
Brett 24 Авг 2014 в 07:32

4 ответа

Лучший ответ

Это преодолело эту проблему, описанную в другом ответе.

find main_directory/ -name "myfile.txt" | tar -czvf mytar.tar.gz -T -
4
Brett 24 Авг 2014 в 09:02

Предполагая, что файлов не так много, вы можете сделать что-то вроде:

cd main_directory/..
find main_directory -name "myfile.txt" | xargs tar zcf mytar.tar.gz

Если файлов много, вы можете передать список файлов в файл / поток и передать его в tar.

find main_directory -name "myfile.txt" -print0 | tar zcf myar.tar.gz --null -T -

Это распечатывает имена файлов, разделенные нулями (от -print0 до find), и инструктирует tar правильно проанализировать это из stdin; использование нулей гарантирует, что любые специальные символы в каталогах обрабатываются правильно

2
Emil Sit 25 Авг 2014 в 14:34
Потрясающий. Спасибо! Это потрясающе. Я думаю, мне нужно узнать о трубах немного больше :-)
 – 
Brett
24 Авг 2014 в 07:48
1
Это будет ужасно, если количество файлов станет слишком большим, чтобы xargs мог построить командную строку, поскольку он будет запускать tar несколько раз и перезаписывать себя (или терпеть неудачу). Возможно, было бы лучше использовать аргумент -T для tar, чтобы указать ему получить список файлов для архивирования из файла и указать использовать /dev/stdin или аналогичный (или просто записать в файл, а затем передайте это tar.
 – 
Etan Reisner
24 Авг 2014 в 07:56
Да, только что столкнулся с этим. Извините за преждевременный ответ... похоже, он работал фантастически. Я думаю, у меня было слишком много файлов (около 1000). Лишь немногие из них были фактически включены в окончательный вариант tar.
 – 
Brett
24 Авг 2014 в 08:30
Я вижу, вы поняли -T; обновил мой ответ, включив в него это, а также трюк с обработкой новой строки, нулей или других специальных символов в именах файлов.
 – 
Emil Sit
25 Авг 2014 в 14:34

С достаточно новой (я полагаю, 4.0.0+) версией bash (и ряда других оболочек) будет работать следующее:

tar -czf mytar.tar.gz main_directory/**/myfile.txt
0
Etan Reisner 24 Авг 2014 в 08:01
Это будет работать, если globstardotglob) включено, но все равно будет срабатывать ARG_MAX и не работать с большим количеством файлов.
 – 
Reinstate Monica Please
24 Авг 2014 в 09:31
Верно. Я хотел упомянуть globstar, но забыл. И да, проблемы с длиной командной строки по-прежнему будут проблемой, но сбой здесь не такой серьезный, как в случае с @EmilSit, поскольку он не заканчивается усеченным (но, по-видимому, полным) tar-архивом (или ошибкой глубоко в процесс tar) и вместо этого сразу же появляются ошибки.
 – 
Etan Reisner
24 Авг 2014 в 17:09

Если структура каталогов действительно такая регулярная, подстановочный знак

main_directory/*/*/files/myfile.txt

Будет соответствовать нужным файлам. Однако, если файлов много, вам может потребоваться вернуться к find / xargs, чтобы избежать проблемы "слишком длинный список аргументов" (ARG_MAX).

Если есть файлы с именем myfile.txt, которые вы не хотите включать, потому что их путь не соответствует в точности подстановочному знаку, безусловно, есть способы исключить их и из find; возможно, тогда это дополнительное ограничение следует указать в вопросе.

0
tripleee 25 Авг 2014 в 14:44