查找文件并将其压缩(带空格)


110

好了,这里的问题很简单。我正在研究一个简单的备份代码。除非文件中有空格,否则它工作正常。这就是我查找文件并将其添加到tar存档中的方式:

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

问题是文件名中有空格时,因为tar认为它是文件夹。基本上有没有一种方法可以在find的结果周围添加引号?还是其他解决方法?


12
最好的使用方法find ... | xargs ...是在每个上使用-print0 / -0参数find -print0 ... | xargs -0 ...。这将导致文件名由空字符分隔,这意味着您可以在文件名中包含空格,换行符或其他奇怪的内容,并且仍然可以使用。
2011年

8
当您有大量文件时,以这种方式使用xargs和tar时会出现问题,xargs将反复调用tar -c,这将继续覆盖您的存档,结果是您将没有想要的所有文件。请参阅下面的详细说明我的答案
史蒂夫·凯莱特

Answers:


217

用这个:

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

它会:

  • 处理带有空格,换行符,前导破折号和其他趣味的文件
  • 处理无限数量的文件
  • 当您有大量文件时tar -cxargs不会像使用with 那样反复覆盖您的backup.tar.gz

另请参阅:


1
如果您想先通过sed几次将发现内容传递给您,该怎么办?例如查找。-print0 | sed /备份/ d | tar ....
Brad Parks

8
请注意,如果有多个条件,则需要添加括号。否则,-print0仅适用于最后一个表达式。例如find . \( -type f -o -name '*.c' \) -print0 | ...
nimrodm 2015年

1
为了好玩,下面是使用cygwin的Windows版本:c:\cygwin\bin\find . -regextype posix-egrep -regex '.*(sln^|vcxproj^|filters)$' -print0 | c:\cygwin\bin\tar -cvf MS_Projects.tar --null -T -
Jon

1
@Steve您能在tar命令末尾解释什么是“-”选项。我在GNU tar的手册页中找不到它。
shaffooo

当然,它是的参数-T,它意味着从标准输入中读取文件名:如果您将单破折号作为`--files-from'的文件名,(即,您指定了--files-from = -或
-T-

14

可能会有另一种方式来实现您想要的。基本上,

  1. 使用find命令将路径输出到要查找的任何文件。将标准输出重定向到您选择的文件名。
  2. 然后使用带有-T选项的tar,该选项允许它获取文件位置的列表(您刚刚使用find创建的位置!)

    find . -name "*.whatever" > yourListOfFiles
    tar -cvf yourfile.tar -T yourListOfFiles
    

这里有一个关于如何使用换行符处理文件名的答案:superuser.com/a/513319/151261
tommy.carstensen


7

为什么不:

tar czvf backup.tar.gz *

确保先使用find然后再使用xargs是明智的选择,但是您很难做到这一点。

更新:Porges评论了一个find-option,我认为这是比我的答案更好的答案,或者另外一个: find -print0 ... | xargs -0 ....


我的完整代码将仅备份在过去一天中修改过的项目。由于它是每日备份,因此我不想重复使用任何信息来节省文件大小(我也每15天进行一次完整备份)。
Caleb Kester

为了使它成为一个更好的SO问题,我将问有关“可靠地一起使用find,xargs和tar”的问题。您的标题和问题并没有真正指定您需要find和xargs,但是您确实需要。
沃伦·P

xargs ... tar c ...如果文件列表过长,将覆盖创建的第一个归档文件,xargs并将tar第二次执行!为了避免覆盖,可以使用,xargs -x但是存档可能不完整。替代方案可以是先进行tar c ...,然后可能反复进行tar r ...。(我对可靠性的贡献:)
pabouk

3

如果您有多个文件或目录,并且想要将它们压缩为独立*.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

将在@Steve Kehlet帖子中添加评论,但需要50个代表(RIP)。

对于通过大量谷歌搜索找到此帖子的任何人,我都找到了一种方法,不仅可以找到给定时间范围内的特定文件,而且还不包括可能导致标定错误的相对路径或空格。(非常感谢您。)

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过滤档案,详细列出已处理的文件,档案名称

编辑2019-08-14:我想补充一点,我也能够在评论中使用基本上相同的命令,只是使用tar本身:

tar -czvf /archiveDir/test.tar.gz --newer-mtime=0 --ignore-failed-read *.pdf

需要--ignore-failed-read在情况有今天没有新的PDF文件。


1

最好的解决方案似乎是先创建文件列表,然后再归档文件,因为您可以使用其他来源并对列表进行其他操作。

例如,这允许使用列表来计算要归档的文件的大小:

#!/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

一个衬板吗?
罗宾诺
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.