我的服务器上的一些文件无意中保存了换行符。它们显示为file?name.txt
查看服务器上的文件时。使用 scp 将这些文件传输到我的本地计算机不起作用,因为我收到“无法写入文件”错误。导致此问题的错误已修复,但我无法访问这些文件。获取这些文件的最佳方式是什么?
答案1
在 Unix 上,换行符与文件名中的任何其他字符一样有效。对于 shell,该字符具有特殊含义(它分隔命令),因此需要像任何其他特殊字符(如空格、;
... |
)一样加引号。
在类似 Bourne 的 shell 中,可以使用单引号或双引号来完成:
ls -d 'a
b'
或者:
ls -d "a
b"
一些 shell(至少ksh93
FreeBSD zsh
)还支持:bash
mksh
sh
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
更可靠地传输文件,例如rsync
or sftp
、 or tar
:
tar cf - src | gzip | ssh user@host 'cd dest && gunzip | tar xpf -'
这也可以更好地保留硬链接、软链接和其他文件属性。如果文件名包含非 ASCII 字符,您可能还需要考虑字符集转换。
答案2
要重命名其中包含换行符(假设换行符是什么)的现有文件,请使用ksh93
、zsh
或:bash
mksh
for f in *$'\n'*; do mv -i -- "$f" "${f//$'\n'/}"; done
glob 模式*$'\n'*
表示匹配任何/所有包含换行符的文件名;该mv
命令通过删除文件中的所有换行符实例来重命名文件。