sed不给我正确的替代操作换Mac的换行 – GNU sed和BSD / OSX sed之间的差异

我使用这个引用: sed help:匹配和replace文字“\ n”(不是换行符)

我有一个文件“test1.txt”,其中包含一个stringhello \ ngoodbye

我用这个命令search并用实际换行符replace“\ n”:

sed -i '' 's/\\n/\n/g' test1.txt 

但结果是: hellongbybye 。 它只是将“\ n”replace为“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 

虽然他们可能与Linux操作系统,MAC操作系统,我得到了以下错误:

 sed: 1: "test1.txt": undefined label 'est1.txt' 

不知道为什么我不能得到这个工作。 提前致谢。

使用BSD / macOS sed ,要在s函数调用的replacestring中使用换行符,则必须使用\ -escaped 实际换行符 – 转义序列\n在那里不受支持(与调用的正则expression式部分不同)。

  • 要么 :只需插入一个实际的换行符:

     sed -i '' 's/\\n/\ /g' test1.txt 
  • 或者 :使用ANSI C引用的string( $'...' )在换行符( $'\n' ;在bashkshzsh )中进行拼接:

     sed -i '' 's/\\n/\'$'\n''/g' test1.txt 

相比之下, GNU sed 识别replacestring中的\n ; 请阅读这两个实现之间差异的综合概述。


GNU sed (Linux)与BSD / macOS sed之间的区别

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

它们的共同点POSIX规定的function:请参阅POSIX sed规范。

最便携的方法仅使用POSIXfunction ,但限制function

  • 值得注意的是,POSIX 仅支持基本的正则expression式 ,这些基本的正则expression式有很多限制(例如,根本不支持| (变更),不支持+? )和不同的转义要求。
    • 警告: GNU sed (不带-r ),支持\| \+\? ,这不符合POSIX标准; 使用--posix来禁用 (见下文)。
  • 仅使用POSIXfunction
    • (两个版本): 使用-n-e选项(特别是,不要使用-E-r打开对扩展正则expression式的支持)
    • GNU sed :添加选项--posix以确保仅用于POSIXfunction(您并不严格需要此function,但如果没有它,最终可能会在不注意的情况下使用非POSIXfunction而不注意; 警告--posix 本身 符合POSIX )
    • 使用POSIX-onlyfunction意味着更严格的格式要求(在GNU sed放弃许多便利):
      • 控制字符序列(如\n\t通常不受支持。
      • 标签和分支命令(如b )后面必须跟一个实际的换行符或通过一个单独的-e选项延续。
      • 详情请参阅下文。

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

  • 他们实现什么扩展不同 (GNU sed实现更多)。
  • 即使是他们所实现的扩展在语法上 部分不同

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

  • 不兼容的function:
    • 不带参数-i选项的使用(不带备份的就地更新)是不兼容的:
      • BSD sed :必须使用-i ''
      • GNU sed :只能使用-i (相当于: -i'' ) – 使用-i ''不起作用。
    • -iGNU sed最新版本的BSD sed (例如,在FreeBSD 10上)中明智地打开了每个input文件的行编号 ,但在10.12版本的macOS没有
      请注意,如果缺less-i 所有版本的数字行, 则会跨越input文件累积
    • 如果最后一个input行没有结尾的换行符 (并被打印):
      • BSD sed总是在输出上附加一个换行符 ,即使input行不结束。
      • GNU sed保留尾随换行符状态 ,即仅当input行结束时才附加换行符。
  • 共同特点:
    • 如果你将你的sed脚本限制在BSD sed支持的地方,他们通常也可以在GNU sed工作 – 除了在-E上使用平台特定的扩展正则expression式特性之外。 显然,你也会放弃特定于GNU版本的扩展。 请参阅下一节。

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

请注意,我正在分别使用BSD和GNU版本的sed使用shorthands macOSLinux ,因为它们是每个平台上的股票版本。 但是,可以在macOS上安装GNU sed ,例如,用brew install gnu-sed使用Homebrew 。

注意除了使用-r-E标志扩展正则expression式)之外,以下指令等同于编写符合POSIX标准的 sed脚本。

  • 对于POSIX合规性,你必须限制自己的POSIX BREs( 基本正则expression式) ,不幸的是,顾名思义,这是非常基本的。
    警告 :不要假设\|\+\? 支持:虽然GNU sed支持它们(除非使用--posix ),BSD sed不支持 – 这些function符合POSIX标准。
    \+\? 可以 POSIX兼容的方式进行仿真
    \{1,\}\+
    \{0,1\}\?
    \| (替代) 不能 ,不幸的是。
  • 对于更强大的正则expression式, 使用-E (而不是-r )来支持ERE( 扩展的正则expression式) (GNU sed不是文件-E ,但是它在那里工作,作为-r的别名; 更新版本的BSD sed ,比如在FreeBSD 10上,现在也支持-r ,但是10.10版本的macOS版本不支持 )。
    警告 :即使使用-r / -E表示您的命令在定义上符合POSIX,您仍然必须将自己限制为POSIX ERE(扩展正则expression式) 。 可悲的是,这意味着你将无法使用一些有用的结构,特别是:

    • 字边界断言,因为它们是特定平台的 (例如,在Linux上是\< ,在OS X上是[[:<]]
    • 在正则expression式中反向引用(而不是在函数调用的replacestring中对“捕获组匹配”的“后向引用”),因为BSD sed扩展正则expression式中不支持它们(但是,奇怪的是, 基本的,POSIX授权的)。
  • 控制字符转义序列,如\n\t

    • 在正则expression式中 (既包括select模式,也包括s函数的第一个参数),假定只有\n被识别为一个转义序列(很less使用,因为模式空间通常是一行(不终止\n )而不是在字符类中 ,因此,例如[^\n]不起作用;(如果您的input不包含\t以外的控制字符,可以用[[:print:][:blank:]]来模拟[^\n] [[:print:][:blank:]] ;否则,拼接控制字符为文字 [2] ) – 通常,包含控制字符作为文字 ,要么通过拼接在ANSI C引号string (例如, $'\t' )支持它( bash, ksh, zsh ),或者通过使用printf命令replace (例如"$(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命令一起使用的replacestring中假设不支持控制字符转义序列 ,所以再次包含控制字符。 作为文字 ,如上所述。

      • 仅限Linux:
        sed 's/-/\t/' <<<$'ab' # -> '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'
      • OR(多个-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上受支持。
      • 如果文本参数因此具有实际的内部换行符,则将其隐藏起来。
      • 如果你想在文本参数之后放置额外的命令,你必须用一个(非转义的)换行符(不pipe是字面还是拼接)来终止它,或者继续单独的-e选项(这是一个适用于所有版本的一般要求) 。
  • 函数列表{...}包含的多个函数调用)中, 一定要在closures}之前终止最后一个函数,
    • 仅限Linux:
    • sed -n '1 {p;q}' <<<$'a\nb' # -> 'a'
    • macOS Linux:
    • sed -n '1 {p;q;}' <<<$'a\nb'

从BSD sed完全没有GNU sed特有的function

如果你需要支持这两个平台,你将错过GNUfunction:

  • 各种正则expression式匹配和replace选项 (包括线select模式和s函数的第一个参数):

  • 逃逸序列

  • 地址扩展 ,比如first~step匹配每first~step行, addr, +N匹配addr N行, – 见http://www.gnu.org/software/sed/manual/sed。; HTML#地址


[1] macOS sed版本比其他类似BSD的系统(如FreeBSD和PC-BSD)上的版本要 不幸的是,这意味着你不能认为在FreeBSD上工作的特性,例如,在macOS上也是一样的。

[2] ANSI C引用的string$'\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'']

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

 sed -i '' 's/\\n/\ /g' test1.txt 

即,使用一个实际的换行符而不是\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. 

另外,在-i选项的描述中,它表示扩展名不是可选的,如果你不需要,你必须指定一个空的参数。 所以一切都最终有意义!