【问题标题】:Find and tar files on Solaris在 Solaris 上查找和 tar 文件
【发布时间】:2014-12-07 02:08:44
【问题描述】:

我的 bash 脚本有点问题。我是unix世界的新手,所以我发现很难处理一个练习。我要做的是在 Solaris 服务器上查找具有特定名称的文件,在特定时间进行修改并将它们归档在一个 .tar 文件中。前两点很容易,但我在尝试存档时遇到了噩梦。问题是,我不断地将整个文件树(最后有文件)归档到 .tar 文件,但我只需要一个文件。我的代码如下所示:

find ~ -name "$maska" -mtime -$dni | xargs -t -L 1 tar -cvf $3 -C

其中$maska 是文件名,$dni 是指修改时间,$3 只是一个存档名称。我发现了 -C 开关,让我跳转到所需文件所在的文件夹,但是当我将它与 xargs 一起使用时,它似乎只是跳转到那里而没有做任何其他事情。

所以我的问题是:

1) 有没有可能以这种方式实现我的目标?

请记住,我不在 gnu tar 上工作。而且我必须使用命令:tar、find。

编辑:我想详细说明我的问题。例如,当我将脚本用于文件 a 时,它应该查找它,因为脚本中显示的点(它是 ~ )并且它会找到的所有内容都应该在一个 tar 文件中。

我现在得到的是(我在 /home/me/Scripts):

-bash-3.2$ ./Script.sh a 1000 backup
 a /home/me/Program/Test/a/ 0K
 a /home/me/Program/Test/a/a.c 1K
 a /home/me/Program/Test/a/a.out 8K

所以脚本已经做了一些打包。接下来我想看看我打包的文件,所以:

 -bash-3.2$ tar -tf backup 
 /home/me/Program/Test/a/
 /home/me/Program/Test/a/a.c
 /home/me/Program/Test/a/a.out

这就是问题所在。 tar 文件中包含所有路径,所以如果我解压它,而不是只获取我想要归档的文件,我会将它们替换到它们的旧位置。对于可视化:

-bash-3.2$ ls
Script.sh*   Script.sh~*  backup
-bash-3.2$ tar -xvf backup 
x /home/me/Program/Test/a, 0 bytes, 0 tape blocks
x /home/me/Program/Test/a/a.c, 39 bytes, 1 tape blocks
x /home/me/Program/Test/a/a.out, 7928 bytes, 16 tape blocks
-bash-3.2$ ls
Script.sh*   Script.sh~*  backup

这就是问题所在。

所以我想要的只是将所有需要的文件(上面示例中的一个)打包到一个没有这些路径的 tar 文件中,所以它只会在我运行 Script.sh 的目录中解压缩。

【问题讨论】:

    标签: unix find solaris tar


    【解决方案1】:

    我不确定你想要什么,但可能就是这样:

    find ~ -name "$maska" -mtime -$dni -exec tar cvf $3 {} +
    

    编辑:在您写完主要问题后的第二次尝试是绝对路径:

    ( cd ~; find . -name "$maska" -type f -mtime -$dni -exec tar cvf $3 {} + )
    

    编辑:第三次尝试,在你写完后你不想在存档中完全没有路径,maska 是一个目录名,$3 需要在当前目录中:

    mkdir ~/foo && \
      find ~ -name "$maska" -type d -mtime -$dni -exec sh -c 'ln -s $1/* ~/foo/' sh {} \; && \
      ( cd ~/foo ; tar chf - * ) > $3 && \
      rm -rf ~/foo
    

    如果由于某种原因~/foo 已经存在,则将~/foo 替换为~/somethingElse

    【讨论】:

    • 不幸的是,这不是我的问题的解决方案。我将在我的第一篇文章中添加更多解释。
    • 好吧,这也绝对不是解决方案。该行使脚本在 ~ 中执行一个 tar 文件,并且它仍然包含所有路径,因此解压它仍然不会在启动脚本的地方提供所需的文件。
    • @Treck 永远不会太晚 ;-)
    【解决方案2】:

    也许你可以这样做:

    #!/bin/bash
    find ~ -name "$maska" -mtime -$dni -print0 | while read -d $'\0' file; do
       d=$(dirname "$file")
       f=$(basename "$file")
       echo $d: $f      # Show directory and file for debug purposes
       tar -rvf tarball.tar -C"$d" "$f"
    done
    

    我手头没有用于测试的 Solaris 盒子 :-)

    【讨论】:

    • 嗯,我明白了它是如何工作的,我真的认为会这样做,但是......仍然有问题。更具体地说,任何地方都没有 .tar 文件。我检查了工作目录和 ~/tmp/ (它甚至不存在!)。但是“发现”部分有效,我检查了它。所以当 - 做,或者 tar 必须对错误负责。也根本没有回声输出。
    • 我只是在我的机器上使用了~/tmp,以免干扰我自己的文件。我会删除它。
    • 是的,仍然没有回应。我想它应该只在我运行脚本的当前目录中创建一个名为 tarball 的 tar 文件。但事实并非如此。
    • 可以在开头添加touch tarball.tar
    • 刚试过这种方式。启动脚本 tarball.tar 后就像我前任的心一样空虚。
    【解决方案3】:

    首先,我的假设: 1.“一个tar文件”,就像你说的,和 2. 没有绝对路径,即如果你备份~/dir/file,你应该可以在/tmp中测试解压得到/tmp/dir/file。

    如果问题是完整路径,你应该替换

    find ~ # etc
    

    cd ~ || exit
    find . # etc
    

    如果 tar 存档不是绝对名称,则应该类似于

    (
    cd ~ || exit
    find . etc etc | xargs tar cf - etc etc
    ) > $3
    

    解释 "(...)" 运行一个子shell,这意味着您在其中更改的某些内容在括号之外没有任何影响;当前目录就是其中之一,所以“(cd 不管是什么;foo)”意味着你运行另一个 shell,改变 its 当前目录,从那里运行 foo,然后你回到你的脚本从未更改过目录。

    “cd ~ || exit”是偏执狂,意思是“cd ~;如果失败,退出”。

    “。”是一个别名,意思是“当前目录,不管它是什么”;玩“找”。 vs "find ~" 如果你不知道是什么意思,你会比我在这里解释的更明白。

    "tar cf -" 表示您在标准输出上创建 tar 存档;我认为语法足够便携,您可能必须将“-”替换为“/dev/stdout”或在 solaris 上可用的任何内容(最简单的解决方案是简单的“tar”,没有“c”命令,但很难读)。

    括号外的最后一个 "> $3" 是输出重定向:不是将输出写入终端,而是将其保存到文件中。

    所以整个脚本是这样的: - 打开一个子shell - 将 subshel​​l 的当前目录更改为 ~ - 在 subshel​​l 中,找到比请求更新的文件,将它们归档,并将生成的 tar 归档的内容写入标准输出 - 子shell的标准输出保存到$3;因为重定向在括号之外,所以相对路径是相对于脚本的 $PWD 解析的,这意味着例如,如果您从 /tmp 目录运行脚本,您将在 /tmp 目录中获得一个 tar 存档(它将在 ~如果重定向发生在子shell中)。

    如果我误解了您的问题,解决方案不起作用或解释不清楚,请告诉我(答案太长,但我已经知道了:)。

    【讨论】:

    • 第一个解决方案保留整个路径!第二个:tar:无法将目录更改为 ./home/me/Program/Test:没有这样的文件或目录,即使它存在......我希望你能提供更多解释,当然当你'会有一段时间;)
    • 我只是吃过晚饭,我的第三个选择是脑残——我现在正在重写它:)
    • Tar 可以工作,但它仍然有整个父目录树......当我解压它时,还有其他目录,并且在它们深处需要文件。我不介意阅读长篇文章,因为它会教给我一些东西;)
    • @Treck 如果您存档 ~/Program/Test/a/a.c 并在 /tmp 中提取结果,您将获得 /tmp/Program/Test/a/a.c;你只是想要 /tmp/a.c 吗?
    • @Treck 还有,“xargs -L 1”意味着它会为每个文件运行一次 tar 调用,你确定这是你想要的吗?
    【解决方案4】:

    pax command 将输出与 tar 兼容的档案,并具有重写路径名所需的灵活性。

    find ~ -name "$maska" -mtime -$dni | pax -w -x ustar -f "$3" -s '!.*/!!'
    

    以下是选项的含义,从手册页中解释:

    • -w 将文件操作数的内容以归档格式写入标准输出(或-f 选项指定的路径名​​)。
    • -x ustar 输出存档格式是 IEEE POSIX 标准中指定的扩展 tar 交换格式。
    • -s '!.*/!!' 根据替换表达式修改文件操作数,使用正则表达式语法。在这里,它会删除每个文件名中从开头到结尾的所有字符/

    【讨论】:

    • 非常感谢您的回答。但正如我在第一篇文章中所说:“我必须使用命令:tar,find。”。但我想我做错了什么,我对我应该做什么有一个不好的概念。我做了一个简单地将所有内容打包到文件夹并对其进行 tar 处理的版本,因为它是我可以使用 tar 获得的最接近的版本。我也会检查你的代码。
    • 好的。 pax 自 Solaris 7 以来一直在 Solaris 中,但我知道您可能有可移植性限制。
    猜你喜欢
    • 1970-01-01
    • 2011-10-30
    • 2017-11-18
    • 2012-07-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-19
    • 1970-01-01
    相关资源
    最近更新 更多