如何解压从最年轻的最古老的一个文件,直到在bash

问题描述:

成功我在一个目录tar文件(备份)的列表,需要解压他们最年轻的尝试最古老的一个,直到成功。如何解压从最年轻的最古老的一个文件,直到在bash

的问题是,不时的tar文件已损坏,需要解压旧的一个。

这是我发现的最年轻的一个,但不知道如何把这个同时,找到下一个。

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

在此先感谢

你已经有一个工作find | xargs ls,让你的文件的排序列表,首先是最新的。 (由于@sjsam指出,它假定关你的文件名包括换行。)你可以使用bash的process-substitution功能,把这个列表中的文件时,每行一个条目,以便它可以被重新ad by a while ... read loop。然后,只要一次备份成功,您就可以退出循环。

# 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做的一样好?)


编辑!又名取3

我被@ sjsam的评论灵感写下ls0,一个ls更换,可以提供空值终止的输出。如果您发现任何错误,请检查并提出问题!它在Cygwin上使用Perl 5.22进行了测试,但应该适用于大多数Perl 5。这是一个单独的文件—安装,把ls0在你的路径和chmod ugo+x ls0

使用ls0,上述技术可以处理奇怪命名文件与沉着:

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'


取2page sjsam links建议使用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))') 

容易,对不对? )

来源:

+0

它是[\ [not suggested \]](http://mywiki.wooledge.org/ParsingLs#Why_you_shouldn.27t_parse_the_output_of_ls.281.29)来解析ls的输出。 – sjsam

+1

@sjsam够公平!看看编辑:)。 – cxw

+0

由于名称中没有空格,因此我使用了第一个版本。 – Alek

下面的脚本将做

find /path/to/tarball/folder -type f -name "*.tar" -printf "%[email protected]%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列出哪些是由前缀的空值终止的压缩包文件上次访问的时间纪元以来秒,这是我们作为分隔符以后使用
  • 一个 --
  • 使用修改时间以降序对文件名进行排序。这就是--分隔符就派上用场了
  • 解析空终止使用while循环
  • 剥去文件名的time--并试图解压它
  • 如果尝试成功,则退出
  • 排序的文件
+1

好东西,但为什么'$?'笨拙的测试? (我假设'$ 0'是一个错字),你可以简单地'&& exit'直接下'tar'(甚至,'而阅读与& !tar;做回声失败>&2; done') –

+0

也许还值得一提的是,这将积累部分来自失败的tar调用的结果,这可能不是您想要的 - 在这种情况下,您可能需要在使用第一个成功的文件之前对每个文件执行一次干运行传递。不过从问题中我们还不清楚需要什么。 –

+0

@TobySpeight:感谢'$?'上的指针。是的!缩短这一个的多种方法。为了解释起见,我放了较长的一个。:) Cheerz – sjsam