没有给我正确的替代操作与Mac换行 - GNU sed和BSD/OSX sed之间的差异

Bra*_*ing 15 macos bsd gnu sed

我正在使用这个参考:sed help:匹配和替换文字"\n"(不是换行符)

我有一个文件"test1.txt",其中包含一个字符串hello \ngoodbye

我使用此命令搜索并用实际的换行符替换"\n":

sed -i '' 's/\\n/\n/g' test1.txt
Run Code Online (Sandbox Code Playgroud)

但结果是:hellongoodbye.它只是将"\n"替换为"n"而不是实际的新行.这与/ t相同,它将留下"t"而不是选项卡.

''是针对MAC中未定义的错误:http://mpdaugherty.wordpress.com/2010/05/27/difference-with-sed-in-place-editing-on-mac-os-x-vs-linux /

更新:

我已经尝试了@ hek2mgl建议的两个命令:

sed -i 's/\\n/\n/g' test.txt
# Or:
sed -i'' 's/\\n/\n/g' test.txt
Run Code Online (Sandbox Code Playgroud)

虽然它们可能适用于Linux,但使用MAC OS时出现以下错误:

sed: 1: "test1.txt": undefined label 'est1.txt'
Run Code Online (Sandbox Code Playgroud)

不知道为什么我不能让这个工作.提前致谢.

mkl*_*nt0 69

随着BSD/MacOS的sed,在使用一个换行符替换字符串的的s函数调用,您必须使用\转义的实际换行符 -转义序列\n支持的有(不像正则表达式调用的一部分).

sed相比之下,GNU 确实\n在替换字符串识别; 继续阅读以全面了解这两种实现之间的差异.


GNU sed(Linux)和BSD/macOS 之间的差异sed

macOS使用[1]BSD版本,它在许多方面与Linux发行版附带的GNU版本不同.sed sed

它们的共同点POSIX规定的功能:参见POSIX sed规范.

最轻便的方法使用POSIX才有的功能,然而,限制功能:

  • 值得注意的是,POSIX 指定基本正则表达式的支持,这些正则表达式具有许多限制(例如,根本不支持|(交替),没有直接支持+?)以及不同的转义要求.
    • 警告:GNU sed(无-r),支持\|,\+并且\?,这是不符合POSIX标准; 使用--posix禁用(见下文).
  • 仅使用POSIX功能:
    • (两个版本):使用-n-e选项(特别是,不要使用-E-r打开对扩展正则表达式的支持)
    • GNU sed:添加选项--posix,以确保只有POSIX的功能(你不严格需要这一点,但没有它,你最终可能会不小心使用了没有注意到非POSIX功能; 警告:--posix 本身符合POSIX标准)
    • 仅使用POSIX功能意味着更严格的格式化要求(放弃GNU中提供的许多便利sed):
      • 通常不支持控制字符序列,例如\n\t.
      • 标签和分支命令(例如b)必须后跟实际换行符或通过单独-e选项继续.
      • 请参阅下文了解详情.

但是,这两个版本都实现了POSIX标准的扩展:

  • 什么他们执行的扩展名不同(GNUsed实现更多).
  • 甚至那些他们实现的扩展部分语法也不同.

如果您需要支持BOTH平台(讨论差异):

  • 不兼容的功能:
    • 使用不带参数-i选项(没有备份的就地更新)是不兼容的:
      • BSD sed:必须使用-i ''
      • GNU sed:必须使用just -i(等效:) -i''- 使用-i ''不起作用.
    • -i明智地接通每输入文件线编号GNU sed最近的版本BSD sed(例如,在FreeBSD 10),但确实NOT在MacOS为10.12.
      请注意,在-i 所有版本中没有数字行累积输入文件.
    • 如果最后输入线并具有尾随换行符(和印刷):
      • BSD sed:总是在输出上附加换行符,即使输入行没有以一个结尾.
      • GNU sed:保留尾随换行符状态,即仅当输入行以一个结尾时才附加换行符.
  • 共同特征:
    • 如果将sed脚本限制为BSD sed支持的脚本,它们通常也可以在GNU中工作sed- 除了使用特定于平台的扩展正则表达式功能之外-E.显然,您还将放弃特定于GNU版本的扩展.见下一节.

跨平台支持指南(OS X/BSD,Linux),受BSD版本更严格的要求驱动:

请注意,我分别使用缩写macOSLinux作为BSD和GNU版本,sed因为它们是每个平台上的库存版本.但是,它可以安装GNU sed在MacOS,例如,使用自制brew install gnu-sed.

注意:除了使用-r-E标志时(扩展正则表达式),下面的说明相当于编写符合POSIX标准的 sed脚本.

  • 对于POSIX兼容性,您必须限制自己使用POSIX BRE(基本正则表达式),不幸的是,正如其名称所示,它非常基本.
    警告:不要假设\|,\+并且\?支持:虽然GNU sed支持它们(除非--posix使用),但BSD sed没有 - 这些功能符合POSIX.
    虽然\+并且\? 可以符合POSIX的方式进行模拟:不幸的是,
    \{1,\}for \+,
    \{0,1\}for \?,
    \|(alternation)不能.
  • 对于更强大的正则表达式,使用-E(而不是-r)支持ERE(扩展正则表达式)(GNU sed没有文档-E,但它确实作为别名-r; BSD的版本sed,例如在FreeBSD 10上,现在也支持-r,但10.10的macOS版本没有).
    警告:即使使用-r/ -E意味着您的命令根据定义而不是 POSIX兼容,您仍然必须限制自己使用POSIX ERE(扩展正则表达式).遗憾的是,这意味着您将无法使用多种有用的结构,特别是:

    • 字边界断言,因为它们是特定\<平台的(例如,在Linux上,[[:<]]在OS X上).
    • 反向引用的正则表达式内(而不是在"反向引用"捕获组中的替换字符串匹配s函数调用),因为BSD sed不支持在扩展正则表达式(但是,奇怪的是,在这样做基本的人,他们是POSIX授权的).
  • 控制字符转义序列,例如\n\t:

    • 在正则表达式中(在选择模式和s函数的第一个参数中),假设只\n被识别为转义序列(很少使用,因为模式空间通常是单行(没有终止\n),但不在字符类中,使得例如,[^\n]不工作;(如果您输入不包含控制字符以外,\t你可以模拟[^\n]使用[[:print:][:blank:]];否则,剪接控制字符作为文字[2] )- 通常,包括控制字符如文字,或者通过在支持它的shell(ksh,)中的拼接ANSI C引用的字符串(例如),或者通过使用(例如)的命令替换$'\t'bash,zshprintf"$(printf '\t')".
      • 仅限Linux:
        sed 's/\t/-/' <<<$'a\tb' # -> 'a-b'
      • macOS Linux:
        sed 's/'$'\t''/-/' <<<$'a\tb' # ANSI C-quoted string
        sed 's/'"$(printf '\t')"'/-/' <<<$'a\tb' # command subst. with printf
    • 在与命令一起使用的替换字符串中s,假设支持NO控制字符转义序列,因此,再次包括控制字符.作为文字,如上所述.

      • 仅限Linux:
        sed 's/-/\t/' <<<$'a-b' # -> 'a<tab>b'
      • macOS Linux:
        sed 's/-/'$'\t''/' <<<'a-b'
        sed 's/-/'"$(printf '\t')"'/' <<<'a-b'
    • 同上为文本参数ia功能:不使用控制字符序列 -见下文.

  • 标签和分支:标签以及标签名称参数bt功能必须跟随或者由文字换行或拼接式$'\n'.或者,使用多个-e选项并在标签名称后面的每个选项终止.
    • 仅限Linux:
      sed -n '/a/ bLBL; d; :LBL p' <<<$'a\nb' # -> 'a'
    • macOS Linux:
      • 有(实际换行):
        sed -n '/a/ bLBL d; :LBL p' <<<$'a\nb'
      • OR(拼接$\n实例):
        sed -n '/a/ bLBL'$'\n''d; :LBL'$'\n''p' <<<$'a\nb'
      • 或(多个-e选项):
        sed -n -e '/a/ bLBL' -e 'd; :LBL' -e 'p' <<<$'a\nb'
  • 函数ia插入/附加文本:在指定文本参数之前,按照函数名称\,后跟文字换行符或拼接符$'\n'.
    • 仅限Linux:
      sed '1 i new first line' <<<$'a\nb' # -> 'new first line<nl>a<nl>b'
    • macOS Linux:
      sed -e '1 i\'$'\n''new first line' <<<$'a\nb'
    • 注意:
      • 没有-e,text参数莫名其妙地不是在macOS输出中换行符(bug?).
      • 不要使用控制字符转义,如\n\t文本的说法,因为他们只支持Linux.
      • 因此,如果text参数具有实际的内部换行符,请\调用它们.
      • 如果要在text参数后面放置其他命令,则必须使用(非转义)换行符(无论是文字还是拼接)终止它,或者继续使用单独的-e选项(这是适用于所有版本的一般要求).
  • 内部功能列表(括在多个函数调用{...}),一定要还终止了最后的功能,收盘前},有;.
    • 仅限Linux:
    • sed -n '1 {p;q}' <<<$'a\nb' # -> 'a'
    • macOS Linux:
    • sed -n '1 {p;q;}' <<<$'a\nb'

sedBSD sed完全缺少GNU 特有的功能:

如果您需要支持这两个平台,您将错过的GNU功能:


[1] macOS sed版本比其他类似BSD的系统(如FreeBSD和PC-BSD)上的版本.不幸的是,这意味着您不能假设在FreeBSD中工作的功能在macOS上可以[相同]工作.

[2] ANSI C引用的字符串$'\001\002\003\004\005\006\007\010\011\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037\177'包含除\n(和NUL)之外的所有ASCII控制字符,因此您可以结合使用它[:print:]来进行非常强大的仿真[^\n]:
'[[:print:]'$'\001\002\003\004\005\006\007\010\011\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037\177'']

  • +1优秀的答案.我只是在黑暗中摸索. (4认同)
  • 好吧,你没有独自摸索......很好的回答,谢谢. (2认同)

oog*_*oga 5

这似乎有点奇怪,但尝试:

sed -i '' 's/\\n/\
/g' test1.txt
Run Code Online (Sandbox Code Playgroud)

即,使用实际换行而不是\n.

解释是你有一个奇怪的sed!有关详细信息,请参阅mac sed手册:https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man1/sed.1.html

s那里的命令描述中,它说:

A line can be split by substituting a newline character into it.  To specify
a newline character in the replacement string, precede it with a backslash.
Run Code Online (Sandbox Code Playgroud)

此外,在-i选项的描述中,它表示扩展名不是可选的,如果您不想要扩展名,则必须指定一个空参数.所以一切都有意义到底!

  • 我收到此错误:“sed:1:“s/\\n//g”:替代模式内未转义的换行符” (2认同)