Shell: rsync 错误地解析文件中的空格 name/path
Shell: rsync parsing spaces incorrectly in file name/path
我正在尝试使用 rsync 通过 ssh 拉取文件列表,但我无法让它处理带有空格的文件名!一个示例文件是这样的:
/home/pi/Transmission_Downloads/FUNDAMENTOS_JAVA_E_ORIENTAÇÃO_A_OBJETOS/2. Fundamentos da linguagem/estruturas-de-controle-if-else-if-e-else-v1.mp4
我正在尝试使用此 shell 代码传输它。
cat $file_name | while read LINE
do
echo $LINE
rsync -aP "$user@$server:$LINE" $local_folder
done
我得到的错误是:
receiving incremental file list
rsync: link_stat "/home/pi/Transmission_Downloads/FUNDAMENTOS_JAVA_E_ORIENTAÇÃO_A_OBJETOS/2." failed: No such file or directory (2)
rsync: link_stat "/home/pi/Fundamentos" failed: No such file or directory (2)
rsync: link_stat "/home/pi/da" failed: No such file or directory (2)
rsync: change_dir "/home/pi//linguagem" failed: No such file or directory (2)
rsync error: some files/attrs were not transferred (see previous errors) (code 23) at main.c(1655) [Receiver=3.1.0]
我不明白为什么它在屏幕上打印正常,但解析文件 name/path 不正确!我知道空格实际上是带空格的反斜杠,但不知道如何解决这个问题。 Sed (find/replace) 也没有帮助,我也尝试了这段代码但没有成功
while IFS='' read -r line || [[ -n "$line" ]]; do
echo "Text read from file: $line"
rsync -aP "$user@$server:$line" $local_folder
done < $file_name
我应该怎么做才能解决这个问题,为什么会这样?
我从 .txt 文件中读取文件列表(每个文件和路径在一行中),并且我使用的是 ubuntu 14.04。谢谢!
shell 正确地将文件名传递给 rsync
,但 rsync
将空格解释为分隔同一服务器上的多个路径。因此,除了双引号变量扩展以确保 rsync
将字符串视为单个参数外,您 还 需要引用文件名中的空格。
如果您的文件名中没有撇号,您可以在双引号内使用单引号:
rsync -aP "$user@$server:'$LINE'" "$local_folder"
如果您的文件名中可能有撇号,那么您需要引用它们(无论文件名是否也有空格)。您可以使用 bash 的内置参数替换来执行此操作(只要您使用的是 bash 4;旧版本,例如 [=69 上提供的 /bin/bash
=] X,此类表达式中的反斜杠和撇号有问题)。这是它的样子:
rsync -aP "$user@$server:'${LINE//\'/\'\\'\'}'" "$local_folder"
丑陋,我知道,但有效。解释在其他选项之后。
如果您使用的是旧版 bash 或不同的 shell,您可以改用 sed
:
rsync -aP "$user@$server:'$(sed "s/'/'\\''/g" <<<"$LINE")'" "$local_folder"
... 或者如果您的 shell 也不支持 <<<
此处字符串:
rsync -aP "$user@$server:'$(echo "$LINE" | sed "s/'/'\\''/g")'" "$local_folder"
说明:我们想将所有撇号替换为.. 在单引号字符串中间变成文字撇号的东西。由于无法对单引号内的任何内容进行转义,因此我们必须先关闭引号,然后添加文字撇号,然后重新打开字符串其余部分的引号。实际上,这意味着我们要用序列(撇号、反斜杠、撇号、撇号)替换所有出现的撇号 ('
):'\''
。我们可以使用 bash 参数扩展或 sed
.
在 bash 中,${varname/old/new}
扩展为变量 $varname
的值,其中第一次出现的字符串 old
被字符串 new
替换.将第一个斜杠 ( ${varname//old/new}
) 加倍会替换 all 次出现,而不仅仅是第一个。这就是我们想要的。但是由于撇号和反斜杠对于 shell 都是特殊的,我们必须在两个表达式中的每个字符前面放置一个(另一个)反斜杠。这会将我们的 old
值变成 \'
,而我们的 new
变成 \'\\'\'
。
sed
版本稍微简单一些,因为撇号并不特殊。反斜杠仍然存在,因此我们必须在字符串中放入 \
才能返回 \
。由于我们希望在字符串中使用撇号,因此使用双引号字符串而不是单引号字符串更容易,但这意味着我们需要将所有反斜杠 再次 加倍以确保shell 将它们传给 sed
不受干扰。这就是 shell 命令具有 \\
的原因:作为 \
传递给 sed
,它输出为 \
.
rsync 默认进行 space 拆分。
您可以使用 -s
(或 --protect-args
)标志禁用它,或者您可以转义文件名
中的 spaces
我正在尝试使用 rsync 通过 ssh 拉取文件列表,但我无法让它处理带有空格的文件名!一个示例文件是这样的:
/home/pi/Transmission_Downloads/FUNDAMENTOS_JAVA_E_ORIENTAÇÃO_A_OBJETOS/2. Fundamentos da linguagem/estruturas-de-controle-if-else-if-e-else-v1.mp4
我正在尝试使用此 shell 代码传输它。
cat $file_name | while read LINE
do
echo $LINE
rsync -aP "$user@$server:$LINE" $local_folder
done
我得到的错误是:
receiving incremental file list
rsync: link_stat "/home/pi/Transmission_Downloads/FUNDAMENTOS_JAVA_E_ORIENTAÇÃO_A_OBJETOS/2." failed: No such file or directory (2)
rsync: link_stat "/home/pi/Fundamentos" failed: No such file or directory (2)
rsync: link_stat "/home/pi/da" failed: No such file or directory (2)
rsync: change_dir "/home/pi//linguagem" failed: No such file or directory (2)
rsync error: some files/attrs were not transferred (see previous errors) (code 23) at main.c(1655) [Receiver=3.1.0]
我不明白为什么它在屏幕上打印正常,但解析文件 name/path 不正确!我知道空格实际上是带空格的反斜杠,但不知道如何解决这个问题。 Sed (find/replace) 也没有帮助,我也尝试了这段代码但没有成功
while IFS='' read -r line || [[ -n "$line" ]]; do
echo "Text read from file: $line"
rsync -aP "$user@$server:$line" $local_folder
done < $file_name
我应该怎么做才能解决这个问题,为什么会这样?
我从 .txt 文件中读取文件列表(每个文件和路径在一行中),并且我使用的是 ubuntu 14.04。谢谢!
shell 正确地将文件名传递给 rsync
,但 rsync
将空格解释为分隔同一服务器上的多个路径。因此,除了双引号变量扩展以确保 rsync
将字符串视为单个参数外,您 还 需要引用文件名中的空格。
如果您的文件名中没有撇号,您可以在双引号内使用单引号:
rsync -aP "$user@$server:'$LINE'" "$local_folder"
如果您的文件名中可能有撇号,那么您需要引用它们(无论文件名是否也有空格)。您可以使用 bash 的内置参数替换来执行此操作(只要您使用的是 bash 4;旧版本,例如 [=69 上提供的 /bin/bash
=] X,此类表达式中的反斜杠和撇号有问题)。这是它的样子:
rsync -aP "$user@$server:'${LINE//\'/\'\\'\'}'" "$local_folder"
丑陋,我知道,但有效。解释在其他选项之后。
如果您使用的是旧版 bash 或不同的 shell,您可以改用 sed
:
rsync -aP "$user@$server:'$(sed "s/'/'\\''/g" <<<"$LINE")'" "$local_folder"
... 或者如果您的 shell 也不支持 <<<
此处字符串:
rsync -aP "$user@$server:'$(echo "$LINE" | sed "s/'/'\\''/g")'" "$local_folder"
说明:我们想将所有撇号替换为.. 在单引号字符串中间变成文字撇号的东西。由于无法对单引号内的任何内容进行转义,因此我们必须先关闭引号,然后添加文字撇号,然后重新打开字符串其余部分的引号。实际上,这意味着我们要用序列(撇号、反斜杠、撇号、撇号)替换所有出现的撇号 ('
):'\''
。我们可以使用 bash 参数扩展或 sed
.
在 bash 中,${varname/old/new}
扩展为变量 $varname
的值,其中第一次出现的字符串 old
被字符串 new
替换.将第一个斜杠 ( ${varname//old/new}
) 加倍会替换 all 次出现,而不仅仅是第一个。这就是我们想要的。但是由于撇号和反斜杠对于 shell 都是特殊的,我们必须在两个表达式中的每个字符前面放置一个(另一个)反斜杠。这会将我们的 old
值变成 \'
,而我们的 new
变成 \'\\'\'
。
sed
版本稍微简单一些,因为撇号并不特殊。反斜杠仍然存在,因此我们必须在字符串中放入 \
才能返回 \
。由于我们希望在字符串中使用撇号,因此使用双引号字符串而不是单引号字符串更容易,但这意味着我们需要将所有反斜杠 再次 加倍以确保shell 将它们传给 sed
不受干扰。这就是 shell 命令具有 \\
的原因:作为 \
传递给 sed
,它输出为 \
.
rsync 默认进行 space 拆分。
您可以使用 -s
(或 --protect-args
)标志禁用它,或者您可以转义文件名