Найти файлы и распаковать их (с пробелами) - PullRequest
106 голосов
/ 05 мая 2011

Хорошо, здесь такая простая проблема.Я работаю над простым резервным кодом.Работает нормально, за исключением случаев, когда в файлах есть пробелы.Вот как я нахожу файлы и добавляю их в архив tar:

find . -type f | xargs tar -czvf backup.tar.gz 

Проблема в том, что в имени файла есть пробел, потому что tar считает, что это папка.Есть ли способ добавить кавычки вокруг результатов поиска?Или другой способ исправить это?

Ответы [ 9 ]

206 голосов
/ 06 сентября 2012

Используйте это:

find . -type f -print0 | tar -czvf backup.tar.gz --null -T -

Это будет:

  • работа с файлами с пробелами, переводом строки, начертыми чертами и прочими забавами
  • обрабатывать неограниченное количество файлов
  • не будет многократно перезаписывать ваш файл backup.tar.gz, как при использовании tar -c с xargs, если у вас большое количество файлов

Также см .:

14 голосов
/ 13 мая 2014

Там может быть другой способ достичь того, что вы хотите.В основном,

  1. Используйте команду find для вывода пути к любым файлам, которые вы ищете.Перенаправьте stdout на имя файла по вашему выбору.
  2. Затем tar с опцией -T, которая позволяет ему получить список местоположений файлов (тот, который вы только что создали с помощью find!)

    find . -name "*.whatever" > yourListOfFiles
    tar -cvf yourfile.tar -T yourListOfFiles
    
8 голосов
/ 05 мая 2011

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

    find . -type f | xargs -d "\n" tar -czvf backup.tar.gz 
7 голосов
/ 05 мая 2011

Почему бы и нет:

tar czvf backup.tar.gz *

Конечно, умно использовать find и затем xargs, но вы делаете это нелегко.

Обновление: Поргес прокомментировал вариант поиска, который, я думаю, является лучшим ответом, чем мой ответ, или другой: find -print0 ... | xargs -0 ....

3 голосов
/ 19 мая 2016

Если у вас есть несколько файлов или каталогов, и вы хотите сжать их в отдельный файл *.gz, вы можете сделать это. Необязательно -type f -atime

find -name "httpd-log*.txt" -type f -mtime +1 -exec tar -vzcf {}.gz {} \;

Это сжимает

httpd-log01.txt
httpd-log02.txt

до

httpd-log01.txt.gz
httpd-log02.txt.gz
2 голосов
/ 10 декабря 2017

Другое решение, как видно здесь :

find var/log/ -iname "anaconda.*" -exec tar -cvzf file.tar.gz {} +
2 голосов
/ 26 апреля 2017

Почему бы не попробовать что-то подобное: tar cvf scala.tar `find src -name *.scala`

1 голос
/ 27 июня 2019

Добавил бы комментарий к @ сообщению Стива Кехлета , но нужно 50 повторений (RIP).

Для тех, кто нашел этот пост через многочисленные поиски в Google, я нашел способ не только найти конкретные файлы с заданным временным диапазоном, но и НЕ включать относительные пути ИЛИ пробельные символы, которые могли бы вызвать ошибки при вызове. (СПАСИБО, СКОЛЬКО СТИВ.)

find . -name "*.pdf" -type f -mtime 0 -printf "%f\0" | tar -czvf /dir/zip.tar.gz --null -T -
  1. . относительный каталог

  2. -name "*.pdf" ищите PDF-файлы (или файлы любого типа)

  3. -type f тип для поиска - это файл

  4. -mtime 0 поиск файлов, созданных за последние 24 часа

  5. -printf "%f\0" Обычный -print0 ИЛИ -printf "%f" НЕ работал для меня. Из справочных страниц:

Это цитирование выполняется так же, как и для GNU ls. Это не тот же механизм цитирования, который использовался для -ls и -fls. Если вы можете решить, какой формат использовать для вывода команды find, обычно лучше использовать «\ 0» в качестве терминатора, чем использовать символ новой строки, поскольку имена файлов могут содержать пробелы и символы новой строки.

  1. -czvf создание архива, фильтрация архива через gzip, подробный список обработанных файлов, имя архива
1 голос
/ 14 января 2015

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

Например, это позволяет использовать список для вычисления размераархивируемые файлы:

#!/bin/sh

backupFileName="backup-big-$(date +"%Y%m%d-%H%M")"
backupRoot="/var/www"
backupOutPath=""

archivePath=$backupOutPath$backupFileName.tar.gz
listOfFilesPath=$backupOutPath$backupFileName.filelist

#
# Make a list of files/directories to archive
#
echo "" > $listOfFilesPath
echo "${backupRoot}/uploads" >> $listOfFilesPath
echo "${backupRoot}/extra/user/data" >> $listOfFilesPath
find "${backupRoot}/drupal_root/sites/" -name "files" -type d >> $listOfFilesPath

#
# Size calculation
#
sizeForProgress=`
cat $listOfFilesPath | while read nextFile;do
    if [ ! -z "$nextFile" ]; then
        du -sb "$nextFile"
    fi
done | awk '{size+=$1} END {print size}'
`

#
# Archive with progress
#
## simple with dump of all files currently archived
#tar -czvf $archivePath -T $listOfFilesPath
## progress bar
sizeForShow=$(($sizeForProgress/1024/1024))
echo -e "\nRunning backup [source files are $sizeForShow MiB]\n"
tar -cPp -T $listOfFilesPath | pv -s $sizeForProgress | gzip > $archivePath
...