修改嵌套在tar存档中的文件

时间:2011-01-21 12:03:09

标签: linux shell unix archive tar

我正在尝试grep然后sed来搜索文件中的特定字符串,这些字符串位于多个tars内,都在一个主tar存档中。现在,我通过

修改文件
  1. 首先解压缩主tar档案。
  2. 然后提取其中的所有焦油。
  3. 然后执行递归grep,然后sed替换文件中的特定字符串。
  4. 最后将所有内容再次打包到tar档案中,以及主档案中的所有档案。
  5. 相当乏味。如何使用shell脚本自动执行此操作?

2 个答案:

答案 0 :(得分:2)

你可能sed实际的tar,因为tar本身不会进行压缩。

e.g。

zcat archive.tar.gz|sed -e 's/foo/bar/g'|gzip > archive2.tar.gz

但是,请注意,还会在文件名,用户名和组名中用条形替换foo,仅在 foo bar <时才有效/ em>长度相等

答案 1 :(得分:2)

除了自动执行您概述的步骤之外,没有多少选择,原因是Kimvais在答案中的警告所证明的原因。

tar修改操作

tar命令有一些修改现有tar文件的选项。但是,由于多种原因,它们不适合您的场景,其中之一是需要编辑的嵌套tarball而不是主tarball。所以,你必须做好工作。

假设

主存档中的所有存档是否都被提取到当前目录或命名/创建的子目录中?也就是说,当你运行tar -tf master.tar.gz时,你会看到:

subdir-1.23/tarball1.tar
subdir-1.23/tarball2.tar
...

或者你看到了:

tarball1.tar
tarball2.tar

(请注意,如果嵌套的tars要嵌入更大的压缩tarball中,它们本身不应该被gzip压缩。)

master_repackager

假设你有子目录符号,那么你可以这样做:

for master in "$@"
do
    tmp=$(pwd)/xyz.$$
    trap "rm -fr $tmp; exit 1" 0 1 2 3 13 15
    cat $master |
    (
    mkdir $tmp
    cd $tmp
    tar -xf -
    cd *        # There is only one directory in the newly created one!
    process_tarballs *
    cd ..
    tar -czf - *   # There is only one directory down here
    ) > new.$master
    rm -fr $tmp
    trap 0
done

如果您在恶意环境中工作,请使用tmp.$$以外的其他内容作为目录名称。但是,这种重新打包通常不是在恶意环境中完成的,并且基于进程ID的所选名称足以为所有内容提供唯一的名称。使用tar -f -进行输入和输出允许您切换目录,但仍然可以在命令行上处理相对路径名。如果你愿意,可能还有其他方法可以解决这个问题。我还使用cat将输入提供给子shell,以便从上到下的流清晰;从技术上讲,我可以在最后使用) > new.$master < $master来改进,但是稍后会隐藏一些关键信息。

陷阱命令确保(a)如果脚本被中断(信号HUP,INT,QUIT,PIPE或TERM),则删除临时目录并退出状态为1(不成功)和(b)一次删除子目录,进程可以以零状态退出。

在覆盖之前,您可能需要检查是否存在新的。$ master。您可能需要检查提取操作是否实际提取了内容。您可能需要检查子tarball处理是否确实有效。如果主tarball提取到多个子目录,则需要将“cd *”行转换为某个循环,该循环遍历它创建的子目录。

如果您对内容有足够的了解并且没有任何问题,可以跳过所有这些问题。

process_tarballs

第二个脚本是process_tarballs;它依次处理命令行中的每个tarball,提取文件,进行替换,重新打包结果等。使用两个脚本的一个好处是,你可以分别从处理一个更大的任务来测试tarball处理包含多个tarball的tarball。如果每个子tarball都提取到自己的子目录中,生活将会更容易;如果其中任何一个提取到当前目录中,请确保为其创建一个新的子目录。

for tarball in "$@"
do
    # Extract $tarball into sub-directory
    tar -xf $tarball
    # Locate appropriate sub-directory.
    (
    cd $subdirectory
    find . -type f -print0 | xargs -0 sed -i 's/name/alternative-name/g'
    )
    mv $tarball old.$tarball
    tar -cf $tarball $subdirectory
    rm -f old.$tarball
done

你也应该在这里添加陷阱以进行清理,这样脚本可以独立于上面的主脚本运行,但仍然不会留下任何中间目录。在外部脚本的上下文中,您可能不需要在创建新脚本之前保持旧的tarball(所以rm -f $tarbal而不是移动和删除命令),所以可能不需要这么小心,但是在它自己的权利,脚本应该小心,不要损坏任何东西。

摘要

  • 你所尝试的并非无足轻重。
  • 可调试性将作业拆分为两个可以独立测试的脚本。
  • 当您知道文件中的内容时,处理角落案例会更容易。