如何将文件从最年轻的文件解压到最老的文件,直到在bash中成功

如何将文件从最年轻的文件解压到最老的文件,直到在bash中成功,bash,while-loop,tar,Bash,While Loop,Tar,我在一个目录中得到了一个tar文件(备份)列表,需要从最年轻的文件到最老的文件进行解压,直到成功 问题是,有时tar文件会被损坏,需要卸载旧的tar文件 这就是我如何找到最年轻的一个,但不知道如何把这个放进去,同时找到下一个 tar -xf `find /config/config_*.tar -maxdepth 1 -type f -size +1k -print0 | xargs -0 ls -hat | head -n 1` 提前感谢您已经有了一个正在运行的find | xargs ls

我在一个目录中得到了一个tar文件(备份)列表,需要从最年轻的文件到最老的文件进行解压,直到成功

问题是,有时tar文件会被损坏,需要卸载旧的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的功能将该列表放入一个文件中,每行一个条目,这样就可以重新创建该列表。然后,您可以在一次备份成功后立即退出循环

    # 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
(正如@sjsam所指出的,
-d'
在功能上等同于
-d$'\0'


Take 2建议使用
perl
而不是
ls
对文件名进行排序。这样,您就可以处理包含换行符或其他奇怪字符的文件名

下面是该技术的一个示例(不是OP问题的答案)。我用一个包含换行符的文件名对它进行了测试。以下代码首先打印当前目录中的
*.tar
文件。此示例在每个文件名前后打印一个斜杠,以便您可以看到带换行符的文件名得到了正确处理。在cygwin、Bash4.3.46和Perl5.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
perl-e'opendir(my$dirh,“.”);打印(连接“\0”、排序{-M$a-M$b}grep/.tar$/、readdir($dirh))'\
|而IFS=read-r-d$'\0'名称
做
printf/%s/\n“$name”
完成
因此,将所有这些放在一起的代码(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
perl-e'opendir(my$dirh,“.”);打印(连接“\0”、排序{-M$a-M$b}grep/.tar$/、readdir($dirh))'\
|读取-r-d$'\0'tarname时
做
tar-xf“$tarname”和break
完成
或者,使用过程替换

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))')
而IFS=read-r-d$'\0'tarname
做
tar-xf“$tarname”和break
完成<下面的脚本就可以了

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
    列出以null结尾的tarball文件,这些文件在自epoch以来的最后一次访问时间(以秒为单位)前加上一个
    --
    ,我们稍后将其用作分隔符
  • 使用修改时间按降序对文件名进行排序。这就是
    --
    分隔符的用武之地
  • 使用while循环分析以null结尾的排序文件
  • 从文件名中删除
    时间--
    ,并尝试将其卸载
  • 如果尝试成功,则退出

好东西,但是为什么要对
$?
进行笨拙的测试呢?(我假设
$0
是一个输入错误)您可以直接在
tar
之后
&exit
(甚至在读取时
,执行echo failure>&2;done
)也可能值得一提的是,这将从失败的tar调用中积累部分结果,这可能不是我们想要的——在这种情况下,在使用第一个成功的文件之前,您可能需要对每个文件执行一次试运行。不过,从这个问题上看,我们不清楚想要什么。@TobySpeight:谢谢你在
$?
上的指针。是的!有多种方法可以缩短这个时间。为了便于解释,我放了长一点的。:)Cheerz@sjsam如果tar的名称包含一个
-->
?@cxw漂亮的点,则不应该
“${stampedfile.*-}”是
“${stampedfile.*-}”(最短匹配)吗,合并..理想情况下,分隔符应该是唯一的,它不应该出现在文件名中。它用于分析ls的输出。我使用了第一个版本,因为名称中没有空格。@sjsam签出-现在您不必再分析ls的输出了!你怎么认为?谢谢你的鼓励,这给了我灵感。:)
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