在Linux服务器上传输文件名中带有换行符的文件

在Linux服务器上传输文件名中带有换行符的文件

我的服务器上的一些文件无意中保存了换行符。它们显示为file?name.txt查看服务器上的文件时。使用 scp 将这些文件传输到我的本地计算机不起作用,因为我收到“无法写入文件”错误。导致此问题的错误已修复,但我无法访问这些文件。获取这些文件的最佳方式是什么?

答案1

在 Unix 上,换行符与文件名中的任何其他字符一样有效。对于 shell,该字符具有特殊含义(它分隔命令),因此需要像任何其他特殊字符(如空格、;... |)一样加引号。

在类似 Bourne 的 shell 中,可以使用单引号或双引号来完成:

ls -d 'a
b'

或者:

ls -d "a
b"

一些 shell(至少ksh93FreeBSD zsh)还支持:bashmkshsh

ls -d $'a\nb'

对于scp,请注意文件名被传递到远程用户的登录 shell。当你这样做时:

scp file user@host:something

它最终调用用户的登录 shellhost来解释:

scp -t something

命令行(至少使用 openssh)。因此,如果该 shell 类似于 Bourne,那么它必须是:

scp 'src/a
b' user@host:"dest/'a
b'"

如果你这样做:

scp 'a
b' user@host:dest/

或者

scp -r src user@host:dest/

服务器上的 sshd 运行:

scp -t dest/

或者

scp -r -t dest/

并且文件名不是在远程shell命令行上传递的,而是嵌入在客户端和服务器之间的数据流中scp。然而我发现(至少对于 openssh 7.2p2)换行符最终转换为\^J(3 个字符)。

因此,您可能需要使用一种不同的机制来ssh更可靠地传输文件,例如rsyncor sftp、 or tar

tar cf - src | gzip | ssh user@host 'cd dest && gunzip | tar xpf -'

这也可以更好地保留硬链接、软链接和其他文件属性。如果文件名包含非 ASCII 字符,您可能还需要考虑字符集转换。

答案2

要重命名其中包含换行符(假设换行符是什么)的现有文件,请使用ksh93zsh或:bashmksh

for f in *$'\n'*; do mv -i -- "$f" "${f//$'\n'/}"; done

glob 模式*$'\n'*表示匹配任何/所有包含换行符的文件名;该mv命令通过删除文件中的所有换行符实例来重命名文件。

相关内容