群晖共享下文件名中出现回车符导致Windows无法读写的处理
前言:
笔者的群晖里面存储的一些文档,突然之间发现不能读取了,尝试打开时Windows系统提示找不到路径。经过再三尝试发现,这些文件可以在Linux下正常读写。在热心网友们的帮助下,经过探索,最终发现不知在哪个阶段、何种原因,文档的名称和扩展名之间被添加了一个回车符(ASCII控制字符,代码:CR,十六进制编码:0x0D,)。而包含这种特殊字符的文件名,在Windows系统下是非法的。最终在网友们的帮助下,解决了这个问题。
简单说一下是如何发现这个特殊字符的。经过热心网友(flaribbit)指导,我使用 ls -l > filename.txt
命令将目录下的文件信息输出到一个txt文本中。然后使用WinHex之类的16进制编辑器直接打开,找到扩展名前的一个字节,查看其数值,然后从ASCII码表中查询即得到结果。
处理过程:
群晖系统的shell太过简单,很多命令不支持,所以我们需要先把其挂载到其他系统中。比如,我挂到了运行Raspbian系统的树莓派下。
Linux系统下挂载CIFS (samba)共享:
以下命令中:
- //Server 是服务器(即群晖)的主机名或IP
- Remote_Diretory 是服务器(即群晖)共享的目录(文件夹)名称。
- Local_Directory 是本地的挂载点,本地的一个空目录(文件夹),需要提前创建好。
- 后面的 username 和 password 是用于访问共享的用户名和密码。
挂载命令:
mount -t cifs //Server/Remote_Diretory Local_Directory -o username=xxx,password=xxx
所有操作完成后记得卸载,卸载命令:
umount <Local_Directory>
替换文件名中的回车符:
知道了原因,我们处理的方法有很多,可以写shell脚本,可以用Python写个小程序。此处笔者使用了Linux下的一个软件,名叫 rename
。这个软件包群晖上没有,所以我将目录挂载到了Raspbian。
如果系统提示找不到rename,使用以下命令获取:
sudo apt install rename
先使用 cd ./Local_Directory/XXX/
来到文件的目录,使用以下命令轻松将该目录下所有文件的名称中的回车符去掉:
rename -v 's/\r//g' *
这样就完成了,如果没有其他问题,此时在Windows系统下已经可以正常读写这些文件了。
考虑Linux系统下的兼容性,如果您想要将文件名称中存在的空格换成 _
,可以使用以下命令:
rename -v 's/ /_/g' *
记得卸载文件系统:
umount <Local_Directory>
以上命令可能看起来有点懵,如果没有学过正则表达式的话。此处稍作解释:
-
-v 是 --verbose,用于在终端中打印成功处理的文件名称,让我们看到处理了哪些文件。
-
's/ /_/g'
正则表示将空格替换成_
,可以看到三个斜杠/
中有两个位置,前面填入的是要匹配的内容,后面填入要改为的内容。如果后面什么都不填(不是空格!),就是将前面要匹配的内容删掉。 -
像是要匹配回车符这样的控制字符,或是特殊字符,我们需要使用转义字符来处理,即在前面添加反斜杠。如回车符是
\r
。
如果我们需要将所有的txt文件的后缀名删除,可以使用以下命令:
rename -v 's/\.txt$//' *.txt
- 正则中
.
前的\
是转义字符。
后记:
经过热心网友们的讨论,我们解决了问题。大佬(Sparkle)提供了使用Python实现的代码,笔者没有测试。
import os
for i in os.listdir('.'):
os.rename(i,i.replace('\r',"))
总结:
遇到问题,我们首先要明白这是个什么问题,如何用简练的文字把问题的现象描述出来。然后在各大搜索引擎中搜索。搜索无果我们回头继续思考,这可能是什么原因?可以借助调试、日志、转储等判断导致问题的原因。最后分析一下,解决问题大致是个什么流程,可以分成哪些步骤,需要学习哪些新的知识,然后一步一步的学习、解决。