Bash 将DOS ^M字符转换为Unix格式失败

Bash 将DOS ^M字符转换为Unix格式失败,bash,sed,Bash,Sed,我正在从一些文件中删除DOS^m字符。如果在单个文件上运行此sed行,它会按预期删除字符: $ sed -i 's/^M//g' somefile.txt 但是,如果我在for循环中从文件列表中拉取同一行,它将不起作用: $ for i in `cat list`; do sed -i 's/^M//g' $i; done 请注意,我可以应用其他命令而不是sed,它们按顺序在每个文件上按预期执行。此外,不会抛出错误(甚至不会抛出代码,因为echo$?返回0)。我也试着引用$I 根据评论中的建

我正在从一些文件中删除DOS^m字符。如果在单个文件上运行此sed行,它会按预期删除字符:

$ sed -i 's/^M//g' somefile.txt
但是,如果我在for循环中从文件列表中拉取同一行,它将不起作用:

$ for i in `cat list`; do sed -i 's/^M//g' $i; done
请注意,我可以应用其他命令而不是sed,它们按顺序在每个文件上按预期执行。此外,不会抛出错误(甚至不会抛出代码,因为
echo$?
返回0)。我也试着引用$I

根据评论中的建议,我尝试使用dos2unix,方法是:

$ for i in `cat list`; do dos2unix $i; done

但一切都没有改变。直接在单个文件上使用dos2unix很好。如果我的列表文件不好,我希望至少会抛出一个错误代码…

首先,我认为
sed
不理解
^M
回车。它应该是
\r

此外,由于UNIX中的文件名可以包含bash的默认字段分隔符,我建议改用while read循环:

while read -r file ; do
    sed -i 's/\r//' "$file"
done < list

顺便说一句,
g
选项在sed命令中没有意义,因为
\r
每行只出现一次。这就是为什么我省略了它。

答案是我在运行命令时输入^M字符时不够小心。正如其他文章所解释的,有必要键入ctrl-v、ctrl-m以输入^m作为单个控制字符


我的问题是,我假设如果一开始是这样输入的,那么在那之后高亮显示并粘贴它就可以了,但对于我正在使用的终端模拟器(guake、tmux)来说,情况并非如此。

不,这完全可以按书面方式工作(假设for循环适用于您所说的其他命令;文件名的详细信息或列表文件的格式可能会把事情搞砸,但这并不取决于您在每个文件上运行的命令)。还有一些不同。我会在读取并引用“$I”时将for循环更改为
但除此之外,很难猜出哪里出了问题。您是否复制/粘贴了字符
^
M
,或者在第二种情况下实际创建了一个Ctrl-M字符。我打赌是复制/粘贴。此外,如果您的文件很大,您可以加快替换速度(稍微)但是将匹配锚定到行的末尾,即
sed的/^M$/'
。最后,您的系统没有
dos2unix文件
?祝您好运。与每天发布和回答的垃圾相比,这是一个完全可以接受的问题(IHMO)。你的问题已经扩展到我们的评论,在我的书中,这始终是一些值得帮助的标志;-)请随意发表你的评论作为答案,并在期限到期时接受它。其他人可能会发表相反的评论。让计票决定;-)祝大家好运@Shelleter,如果经过足够的编辑,不再让人们对实际问题不感兴趣(也不再将误导性内容作为问题的一部分),我可以看到这篇文章保持开放。然而,事实上,这只是一种误导。
sed
确实理解的
^M
是一个单一字符,在大多数unix环境中是通过使用^V转义创建的,即按
Ctrl-V
然后按
Ctrl-M
。这将显示为
^M
,与键入为
^
M
的两个单独字符不同。有一些unix实用程序确实理解2字符
^M
Ctrl-M
stty
(我认为)是最常见的。这个问题看起来像是按字面意思键入的
^
M
。也许这就是根本原因在评论中,O.P.表示他意识到并使用了ctrl-v、ctrl-m,但后来意识到他并不一致,在创建for循环时使用了复制/粘贴。我对你的优秀答案的评论是,把记录直接放在
^
M
vs
^M
;-)
find PATH_TO_FILES -type f -name 'NAME' ... -exec sed -i 's/\r//' {} \;