我该如何通过ssh解压多个tar文件?

5

我正尝试通过ssh解压多个tar文件:

ssh user@hostname "cat /dir/file*.tgz" | tar xvzf -

上述方法仅适用于远程服务器上的第一个文件匹配项。本地(目标)服务器只接收一个文件。但是通配符已被验证可匹配多个文件。
是否有其他方法可以实现此功能?

3
这并不是一个SSH的问题;即使您在本地工作,也会看到相同的行为(例如 cat /dir/file*.tgz | tar xvzf -)。 - Oliver Charlesworth
谢谢Oli,这确实是一个有用的建议。你知道另外一种方法吗? - CarpeNoctem
你能否使用SCP代替SSH? - Oliver Charlesworth
是的,我可以使用scp然后提取。只是在寻找最简洁的方法,scp是我的备选方案。 ;) - CarpeNoctem
5个回答

4

另一个想法是,避免多次使用 ssh 命令以及 scp 命令(因为这两个命令至少需要来回传递每个文件一次):

ssh user@hostname 'tar cf - /dir/file*.tgz' | tar xf - --to-command='tar xzvf -'

我们在服务器端使用一个 tar 调用将所有文件打包在一起,在客户端再次使用第二个 tar 调用将它们解压,然后对每个条目调用 tar xzv。这类似于sehe的base64答案,但更高效,因为它不会让文件变大。

1
好的,不过有GNU tar --catenate -f existing.tar appendix*.tar,但是(a)它不能进行流式传输 (b) 它不能处理压缩存档。 - sehe
是的,我不想将多个存档文件追加到一个文件中,而只是提取多个存档文件的内容,这些存档文件作为一个流输入。 我有一个更好的想法,现在正在编辑。 - Paŭlo Ebermann
感谢你们所有人。你们都是Unix学者,这是我看过的最有趣的问题之一。 - CarpeNoctem
啊,这主要是基本的Unix工作知识(例如管道是什么),再加上阅读tar手册页的组合。但我很高兴我们能帮忙。 - Paŭlo Ebermann

2
mkdir /tmp/tars
scp 'user@hostname:/dir/file*.tgz' /tmp/tars/
foreach tarname in /tmp/tars/*.tgz; do tar xzvf "$tarname"; done

如果绝对不能存储临时副本:

ssh user@hostname 'ls /dir/file*.tgz' | while read tarname; 
do
    ssh user@hostname "cat '/dir/$tarname'" | tar xzvf -
done

那么,我敢问吗?你确定其他存档是(a)有效的(b)非空的吗? - sehe
2
嗯,这需要多个 ssh 连接。 - Paŭlo Ebermann
在这里,您可能需要使用 ls -1 列出每个文件并将其放在新行上。否则,read 将一次读取多个文件。 - Paŭlo Ebermann
1
@Paulo:真的吗?当标准输出不是TTY时,ls在什么系统上会输出多列? - John Zwinck
@John:说得好。我刚试图找到一个解释CarpeNoctem的观察。 - Paŭlo Ebermann
显示剩余4条评论

1
您可以将此包装在查找调用中,然后使用exec开关迭代每个找到的文件。
ssh user@hostname 'find /path/to/dir -name "*.tar.gz" -exec tar xvf "{}" ";"'

单个ssh调用,无需编写bash脚本。


0

CarpeNoctem的启发让我更进一步,提供了一个一站式解决方案,只需要一个SSH连接,就可以完成所有流媒体相关工作。

经过测试的概念证明(一行代码格式化以提高可读性):

 (echo '#!/bin/sh'; 
  for a in /dir/file*.tgz
  do 
      echo 'base64 -d <<"TARIMAGE" | tar xvzf -'
      base64 "$a"
      echo "TARIMAGE"
  done) | ssh -C remote 'cd /targetdir && sh -'

当然,您实际上想要反转本地和远程的角色,在这种情况下,我建议将脚本生成放到shell脚本中:
gen_script.sh,chmod + x
#!/bin/bash
echo '#!/bin/sh'; 
for a in /dir/file*.tgz
do 
    echo 'base64 -d <<"TARIMAGE" | tar xvzf -'
    base64 "$a"
    echo "TARIMAGE"
done

调用

scp gen_script.sh user@hostname:
ssh -C user@hostname /home/user/gen_script.sh | (cd targetdir && sh -)

未完成的部分,思考:

  • 您可以使用uuencode、od、xxd、pgp或其他替代base64
  • 您可以在ssh上启用压缩(ssh -C)以进一步优化带宽
  • 我自己添加了targetdir/步骤以防止意外;如果您不需要它,可以省略它 :)

0

使用文件比使用命令更容易。因此,与其使用ssh命令访问远程主机和tar命令访问存档,不如使用SSHFS文件系统访问远程主机上的文件。

mkdir hostname-dir.tmp
sshfs user@hostname:/dir hostname-dir.tmp
for a in hostname-dir.tmp/*.tgz; do tar xvf "$a"; done
fusermount -u hostname-dir.tmp

你甚至可以更进一步,使用AVFS将存档文件作为目录¹访问。所有这些都由FUSE提供,它是一个通用的框架,可以将各种东西作为文件进行访问。

mountavfs
mkdir hostname-dir.tmp
sshfs user@hostname:/dir hostname-dir.tmp
for a in ~/.avfs$PWD/hostname-dir.tmp/*.tgz; do cp -Rp "$a#"/* .; done
fusermount -u hostname-dir.tmp

如果你的shell是zsh,那么这个for循环可以被glob qualifier替换。
cp -Rp ~/.avfs$PWD/hostname-dir.tmp/*.tgz(e\''reply=($REPLY\#/*)'\') .

¹ AVFS也可以通过SSH访问远程文件,但我认为您不能以此方式访问远程存档:AVFS路径只有一个跳跃点。因此仍然需要SSHFS。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接