如何解压从最小到最旧的文件,直到bash成功

时间:2016-12-15 15:02:30

标签: bash while-loop tar

我在目录中找到了tar文件(备份)的列表,需要解压它们从最小到最旧的尝试,直到成功。

问题是tar文件有时会被破坏,需要解开较旧的文件。

这就是我找到最年轻的一个,但不知道如何把它放进去,然后找到下一个。

tar -xf `find /config/config_*.tar -maxdepth 1 -type f -size +1k -print0 | xargs -0 ls -hat | head -n 1`

提前致谢

2 个答案:

答案 0 :(得分:1)

您已经有了一个工作find | xargs ls,它为您提供了最新的文件排序列表。 (正如@sjsam指出的那样,假设你的文件名都没有包含换行符。)你可以使用bash的process-substitution功能将该列表放在一个文件中,每行一个条目,这样它就可以重新{{ 3}}。然后,只要一次备份成功,就可以退出循环。

    # vvvvvvvvvvvvvvvvvvvvvv get the next filename into $tarname
while IFS= read -r tarname
do  
    tar -xf "$tarname" && break
                    #  ^^^^^^^^ done with the loop if tar succeeds
done <   <(find /config/config_*.tar -maxdepth 1 -type f -size +1k -print0 | xargs -0 ls -hat)  
   # ^   ^^^^---- the process substitution
   # |
   # +--------- the redirection from the process subsitution

请注意,您需要< <(...),而不仅仅是<(...)

(顺便说一下,您需要ls -hat,还是ls -t也会这样做?)

编辑!又名 Take 3

我受到了@ sjsam评论的启发,写了ad by a while ... read loopls替换,可以提供以NULL结尾的输出。如果您发现任何错误,请检查并提出问题!它在Cygwin上使用Perl 5.22进行了测试,但对大多数Perl 5s都适用。这是一个单独的文件 - 要安装,将ls0放在您的路径中chmod ugo+x ls0

使用ls0,上述技术可以使用aplomb处理奇怪命名的文件:

while IFS= read -r -d '' tarname
do  
    tar -xf "$tarname" && break
done <   <(find /config/config_*.tar -maxdepth 1 -type f -size +1k -print0 | ls0 -t)

(正如@sjsam所说,-d ''在功能上等同于-d $'\0'

选择2 ls0建议使用perl代替ls对文件名进行排序。这样你就可以处理包含换行符或其他奇怪字符的文件名。

以下是该技术的一个示例(不是OP问题的答案)。我用包含换行符的文件名测试了它。以下代码首先打印当前目录中的*.tar个文件。此示例在每个文件名之前和之后打印斜杠,以便您可以看到具有换行符的文件名已正确处理。测试了cygwin,bash 4.3.46,perl 5.22.2。

perl -e 'opendir(my $dirh, "."); print(join "\0", sort { -M $a <=> -M $b } grep /.tar$/, readdir($dirh))' \ 
| while IFS= read -r -d $'\0' name
do 
    printf "/%s/\n" "$name"
done

所以,将这一切放在一起代码(1)回答OP的问题,(2)对于具有奇怪内容的文件名是健壮的:

perl -e 'opendir(my $dirh, "."); print(join "\0", sort { -M $a <=> -M $b } grep /.tar$/, readdir($dirh))' \ 
| while read -r -d $'\0' tarname
do
    tar -xf "$tarname" && break
done

或者,使用流程替换,

while IFS= read -r -d $'\0' tarname
do
    tar -xf "$tarname" && break
done < <(perl -e 'opendir(my $dirh, "."); print(join "\0", sort { -M $a <=> -M $b } grep /.tar$/, readdir($dirh))')

简单,对吗? ;)

来源:

答案 1 :(得分:1)

下面的脚本将

find /path/to/tarball/folder -type f -name "*.tar" -printf "%A@--%p\0" |
sort -rnz | while read -r -d '' stampedfile 
do
  tar -xzf "${stampedfile#*--}" >/dev/null 2>&1
  [ $? -eq 0 ] && echo "Newest Working Tar: ${stampedfile#*--}" && exit
done

我们做了什么

  • 使用find列出空白终止的tarball文件,这些文件在上一次访问的时间(自纪元以来以秒为单位)和我们稍后用作分隔符的--之前列出
  • 使用修改时间按降序对文件名进行排序。这是--分隔符派上用场的地方
  • 使用while循环
  • 解析空终止的已排序文件
  • 从文件名中删除time--并尝试解压缩
  • 如果尝试成功,则退出