【问题标题】:Command line text find/replace for ^M (\r) and ^K (\v)^M (\r) 和 ^K (\v) 的命令行文本查找/替换
【发布时间】:2015-04-26 12:23:59
【问题描述】:

我正在尝试编写一个 shell 脚本,它(除其他外)将用新行替换 windows 行尾 (^M) 和垂直制表符 (^K)。 Sed 看起来像是要使用的工具,但我不太明白。我不明白为什么这不起作用..

$ sed -i 's/^K/\n/g' article_filemakerExport.xml 
sed: 1: "article_filemakerExport ...": command a expects \ followed by text

注意:我正在使用 mac。

【问题讨论】:

  • dos2unix 不能满足您的需求吗?

标签: macos bash text replace sed


【解决方案1】:

在 Windows 行结束时,您想删除 ^M(或 \r 或回车),但您似乎想用换行符替换 ^K。

我使用的命令是tr,两次。

tr -d '\r' < article_filemakerExport.xml | tr '\13' '\12' > tmp.$$ &&
mv tmp.$$ article_filemakerExport.xml || rm -f tmp.$$

鉴于一个操作是删除,另一个是替代操作,我认为您不能将它们组合成一个 tr 调用。如果您担心链接等问题,可以使用cp tmp.$$ article_filemakerExport.xml; rm -f tmp.$$

您还可以使用 dos2unix 将 CRLF 转换为 NL 行尾而不是 tr

注意tr是一个纯过滤器;它只读取标准输入,只写入标准输出。它不直接读取或写入文件。


实际上,我需要用换行符替换这两个。

这更容易:一次调用 tr 就可以完成这项工作:

tr '\13\15' '\12\12' < article_filemakerExport.xml > tmp.$$ &&
mv tmp.$$ article_filemakerExport.xml || rm -f tmp.$$

或者,如果您愿意:

tr '\13\r' '\n\n' < article_filemakerExport.xml > tmp.$$ &&
mv tmp.$$ article_filemakerExport.xml || rm -f tmp.$$

我认为 control-K 没有 \z 样式的表示法,但我愿意学习其他方式(可能是垂直制表符,\v)。

(在Ed Morton的提示处添加了&amp;&amp;|| rm -f tmp.$$命令。)


控制字符的部分列表

 C Oct Dec Hex Unicode Name
\a 07   7  07  U+0007 BELL
\b 10   8  08  U+0008 BACKSPACE
\t 11   9  09  U+0009 HORIZONTAL TABULATION
\n 12  10  0A  U+000A LINE FEED
\v 13  11  0B  U+000B VERTICAL TABULATION
\f 14  12  0C  U+000C FORM FEED
\r 15  13  0D  U+000D CARRIAGE RETURN

您可以在 Unicode 站点 (http://www.unicode.org/charts/PDF/U0000.pdf) 上找到这些控制字符的完整集。毫无疑问,还有许多其他可能的地方值得一看。

【讨论】:

  • 在您第一次调用 tr 时,我认为您需要重定向而不是指定文件名。有了这个固定,你的答案比我的要好,因为 tr 是标准的,而 dos2unix 并不总是可用。
  • 谢谢,@PeterBowers;是的,它缺少了一个&lt;,我非常清楚这是需要的(见证最后一段)。
  • doub1ejack,我想您会发现@JonathanLeffler 的回答正是您想要的。 DOS/Windows“换行符”实际上是 2 个字符,当您删除 \r 时,它会留下 UNIX 换行符。然后在他的第二个 tr 中,他将 \013(八进制的 ^K)更改为 \12(UNIX 换行符)。因此 DOS 换行符和 ^K 都转换为 UNIX 换行符。试试看 - 你会喜欢的... :-)
  • @EdMorton:很公平……也改变了这一点。
  • ^G 是 BEL,或\a,或\007(詹姆斯邦德字符)或\7(这些是八进制常量,带或不带前导零)。我将在主要答案中添加一些关于控制字符名称的注释。 ^K 也是“垂直制表”,所以 \v 可能会映射到那个(它在我的 Mac 上为我做了)。
【解决方案2】:
dos2unix <article_filemakerExport.xml | tr '\013\015' '\n\n'

【讨论】:

  • 这里为什么需要dos2unix?看起来这可能只是将信息传递到tr 的一种更安全的方式?它对文本有什么其他作用吗?
  • 我看到它用换行符替换了 dos 回车符。但仅当它们位于行尾时。我有^M 字符散布在整个文本行中......
  • 啊,在您的问题中,您特别提到了 windows 行尾,然后将 ^M 放在括号中。我们假设您的意思是真正的 Windows 行尾,实际上是 \r\n。我会相应地编辑我的答案。
【解决方案3】:

一个 BSD (OS X) sed 解决方案,由 ANSI C-quoted bash strings 协助:

sed -i "" $'s/\r$/\\\n/g; s/\v/\\\n/g' article_filemakerExport.xml

注意:

  • BSD sed - 不像 GNU sed - 需要一个带有 -i 选项的参数;因此,为了表明应该创建 no 备份文件,必须传递一个 空字符串 ("") - 请参阅下文了解如何解释您遇到的错误。
  • 该命令将\r\n 替换为\n\n 而不是\n,这就是我理解您想要的(仅获得\n,只需将第二个替换字符串设为空;即使没有替换\r后面直接跟\n,去掉\r后面的$)。

这是一个带有示例输入的概念证明:

$ sed  $'s/\r$/\\\n/g; s/\v/\\\n/g' <<<$'one\vtwo\r\nthree\nfour'
one
two

three
four

(上面输出中的所有换行符都是\n。)

  • 需要一个 ANSI C 引用的字符串 ($'...') 来弥补 BSD sed 中对转义序列的支持不足:shell 创建所需的控制字符 ($'\v' 创建垂直制表符 (^K; @ 987654342@ 也可以),$'\r' CR(^M),$'\n' 换行)并将结果文字传递给sed
  • \\\n 导致文字 \ 后跟文字换行符 - BSD sed 要求替换字符串中的文字换行符为 \-转义(并且不支持转义代码 \n)。李>

至于为什么你的命令不起作用

注意:看起来您的问题至少部分源于假设 BSD sed 与 GNU sed 的工作方式相同,不幸的是,情况并非如此:有许多微妙的而不是这样细微差别 - 见https://stackoverflow.com/a/24276470/45375

  • -i 选项缺少参数导致 sed 将您的 程序 解释为 -i 参数,并将您的 文件名 解释为程序。由于您的文件名以 a 开头,sed 看到了 a(附加文本)命令,并被文件名的其余部分阻塞(因为它不是有效的 a 命令)。
  • 即使修复缺少的-i 选项参数也不会使命令工作,原因如上(简而言之:不支持控制字符。转义序列),以及您尝试表示垂直选项卡作为字符串^K(在GNU sed 中,您可以直接使用\v)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-02-09
    • 2022-01-09
    • 2017-03-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-19
    • 1970-01-01
    相关资源
    最近更新 更多