split 过滤器中的环境变量

split 过滤器中的环境变量

split因此,我正在尝试使用如下方法获取大型块设备的内容:

split --bytes 10M --numeric-suffixes --filter='cat | ssh root@$remote_ip "gzip >> /root/myfilecopy.gz"' /dev/myblockdev

但是,当我将远程文件名保存在环境变量中并在 中使用该变量splitfilter,它不起作用:

remote_file=/root/myfilecopy.gz
split --bytes 10M --numeric-suffixes --filter='cat | ssh root@$remote_ip "gzip >> $remote_file"' /dev/myblockdev

这是我得到的:

bash: -c: line 0: syntax error near unexpected token `newline'
bash: -c: line 0: `gzip >> '
split: with FILE=x00, exit 1 from command: cat | ssh [email protected] "gzip >> $remote_file"

看起来环境变量在过滤命令中没有正确扩展。

有任何线索知道如何修复此问题吗?

谢谢。

答案1

太复杂了?

暂时把变量放在一边。这是你的基本代码:

 split --bytes 10M --numeric-suffixes --filter='cat | ssh root@$remote_ip "gzip >> /root/myfilecopy.gz"' /dev/myblockdev

首先:cat在这里没用

接下来,我认为将连续的 -s 的结果附加gzip到同一个文件 ( >>) 会取消 的工作split。理论上,最后你得到的只是 gzip 压缩的/dev/myblockdev,就像你所做的一样:

ssh root@$remote_ip 'gzip > /root/myfilecopy.gz' < /dev/myblockdev

实际上,我会考虑竞争条件。我确实希望在本地按顺序split运行-s;但如果在某些情况下,远程端的各种缓冲区或滞后导致下一个开始写入,而前一个完成,我也不会感到惊讶。这会损坏。只打开文件一次可以避免这种情况。sshgzipmyfilecopy.gz

如果您使用$FILE(请参阅man 1 split)并写入多个文件,我会看到使用的意义split。请注意,这不会引入竞争条件,因为每个文件都只会打开一次。

结论:split可能没用,cat肯定没用;粗心的附加可能会损坏生成的文件。


您询问的问题

好的,让我们假设您有理由使用这种split方式>>cat尽管您的方式仍然没用)。

您当前的 shell 知道 的值$remote_file,但split及其过滤器是子进程,除非您export事先指定,否则它们不会继承该变量。不存在的变量将扩展为空,因此相关片段看起来像gzip >> (newline),因此出现错误。

同样适用于$remote_ip。我猜你的代码中你没有使用$remote_ip实际的 IP 地址192.168.0.105。从现在起,我remote_ip使用占位符(即不是 shell 变量)表示实际的 IP 地址。

export

remote_file="/root/myfilecopy.gz"
export remote_file
# now your split command should utilize the variable as you expected

$remote_file或者,您可以在运行 时扩展当前 shell split。最初,$remote_file字符串保持不变,因为它被单引号括起来。以下语法仅针对这一个变量更改引号的类型:

split --bytes 10M --numeric-suffixes --filter='ssh root@remote_ip "gzip >> '"$remote_file"'"' /dev/myblockdev
#                                                     close a single quote ^              ^ and open again
#                                             variable inside double quotes ^^^^^^^^^^^^^^

这种方式split永远不会得到字面意思$remote_file,而是得到它的价值。


另一个问题

如果您有remote_file="/root/myfile copy.gz",路径中的空格会将其拆分为远程端的两个参数。因此,更强大的方法需要额外的引号。这是上述带有额外引号(用 转义\)的“无导出”方法:

split --bytes 10M --numeric-suffixes --filter='ssh root@remote_ip "gzip >> \"'"$remote_file"'\""' /dev/myblockdev

让我们一步一步地剥离它。除其他参数外,split将以下内容视为一个参数:

--filter=ssh root@remote_ip "gzip >> \"/root/myfile copy.gz\""

它将在以下位置运行此过滤器bash

ssh root@remote_ip "gzip >> \"/root/myfile copy.gz\""

然后ssh就会看到这是它的一个论点:

gzip >> "/root/myfile copy.gz"

因此在远程端,重定向将是"/root/myfile copy.gz"。如果没有添加这些引号,您将得到:

gzip >> /root/myfile copy.gz

相当于

gzip copy.gz >> /root/myfile

补充笔记

  • 如果本地 CPU 足够快,请考虑gzip之前ssh。这样,您可以通过网络链接推送更少的数据;特别是如果您准备好块设备以进行良好的压缩
  • 如果您的目的是运行多个gzip进程以充分利用多个 CPU 核心,那么请注意,它们可能还是会按顺序运行;如果不是,则会出现竞争条件 — — 您不希望出现这种情况。熟悉pigz

相关内容