【问题标题】:Insert newline (\n) using sed使用 sed 插入换行符 (\n)
【发布时间】:2023-03-26 19:12:01
【问题描述】:

我正在尝试将一些列表清理为格式正确的 CSV 文件以进行数据库导入。

我的起始文件看起来像这样,每个“行”应该跨越多行,如下所示

Mr. John Doe
Exclusively Stuff, 186 
Caravelle Drive, Ponte Vedra
33487. 

我创建了一个清理文件的sed 脚本(有很多“脏”格式,例如逗号前后的双空格和空格)。 问题是带有句号的 Zip。 我想将句号更改为新行,但无法正常工作。

我使用的命令是:

sed -E -f scrub.sed test.txt

scrub.sed脚本如下:

:a
N
s|[[:space:]][[:space:]]| |g
s|,[[:space:]]|,|g
s|[[:space:]],|,|g
s|\n| |g
s|[[:space:]]([0-9]{5})\.|,FL,\1\n |g
$!ba

我得到的是

Mr. John Doe,Exclusively Stuff,186 Caravelle Drive,Ponte Vedra,FL,33487n 

如果认为 Zip+.(句号) 将是一个很好的“分隔符”来使用替换,虽然我可以找到它,但我似乎无法告诉它在那里放一个换行符。

我在网上找到的大部分内容都是关于用其他东西替换换行符(通常是删除它们),但用换行符替换的内容不多。我确实找到了这个,但是没有用:How to insert newline character after comma in `),(` with sed?

我有什么遗漏吗?

更新:

我编辑了我的 scrub.sed 文件,按照指示放置了文字换行符。还是不行

:a
N
s|[[:space:]][[:space:]]| |g
s|,[[:space:]]|,|g
s|[[:space:]],|,|g
s|\n| |g
s|[[:space:]]([0-9]{5})\.|,FL,\1\
|g
$!ba

我得到的是(所有内容都在一行中):

Mr. John Doe,Exclusively Stuff,186 Caravelle Drive,Ponte Vedra,FL,33487 Mrs. Jane Smith,Props and Stuff,123 Main Drive,Jacksonville,FL,336907  

我的预期输出应该是:

Mr. John Doe,Exclusively Stuff,186 Caravelle Drive,Ponte Vedra,FL,33487
Mrs. Jane Smith,Props and Stuff,123 Main Drive,Jacksonville,FL,336907  

【问题讨论】:

  • 这里似乎工作得很好。使用相同的文件和脚本,我在最后用换行符重新格式化数据。将\n\n 放在 sed 脚本的倒数第二行中会给我两个换行符,正如预期的那样。 (但是,“Doe”和“Exclusively”之间没有逗号)。我在 Linux 上使用 (GNU sed) 4.4。您使用的是哪个版本/平台?
  • 我在 FreeBSD 上使用 sed
  • 啊,我明白了。如果可以的话,也许可以尝试使用 GNU sed?我还看到我在输出中得到了“,FL”,就像你从脚本中想要的那样。您确定您提供的输出来自您提供的脚本吗?
  • 没错。我在尝试混淆真实数据时无意中删除了 FL。
  • 考虑不要删除邮政编码后的换行符。将 s|\n| |g 更改为 s|\([^[:space:]]\)\n\([^[:space:]]\)|\1 \2|g 以便仅转换后面带有字符的换行符。这样您就不必恢复未删除的内容。

标签: bash sed freebsd


【解决方案1】:

BSD 上的sed 不支持新行的\n 表示(将其转换为文字n):

$ echo "123." | sed -E 's/([[:digit:]]*)\./\1\n next line/'
123n next line

GNU sed 确实支持 \n 表示:

$ echo "123." | gsed -E 's/([[:digit:]]*)\./\1\nnext line/'
123
next line

替代方案是:

使用单个字符分隔符,然后使用 tr 转换为新行:

$ echo "123." | sed -E 's/([[:digit:]]*)\./\1|next line/' | tr '|' '\n'
123
next line

或者在你的 sed 脚本中使用转义的文字换行:

$ echo "123." | sed -E 's/([[:digit:]]*)\./\1\
next line/'
123
next line

或者定义一个新行:

POSIX:

nl='
'

支持ANSI C quoting的BASH/zsh/其他人:

nl=$'\n'

然后使用 sed 加上适当的引用和转义来插入文字 \n

echo "123." | sed 's/\./'"\\${nl}"'next line/'
123
next line

或者使用awk:

$ echo "123." | awk '/^[[:digit:]]+\./{sub(/\./,"\nnext line")} 1'
123
next line

或者使用支持\n的GNU sed

【讨论】:

  • 我试图在我的 sed 脚本中使用转义文字,如图所示,但无论出于何种原因,它都不起作用。但是,回复:您所说的 BSD 不支持 \n,我将改变策略以合并 tr。我永远不会猜到它不受支持。谢谢!
  • 我正在尝试在我的 sed 脚本中使用转义文字,如图所示,但无论出于何种原因,它都不起作用。sed 脚本中很难做到与一行sed。您还可以使用多字符分隔符(例如<!!>),然后使用awk 将其更改为\n。老实说,POSIX sed 最适合仅用于单行更改。
  • @EdMorton:我想我没有尝试用文字换行来调试他的脚本。我确实记得(作为 BSD 用户)我觉得它应该工作但没有工作的时候挠头。
  • 是的,Solaris sed 更糟糕。如果不是简单的s/old/new/,那么您将进入涉及每个标点符号、单个字母和蝙蝠侠符号的混杂符文的不同组合,每个字符的含义都在逐个逐个地变化。因此 awk.... :-)。
  • @EdMorton 迫不及待想看到一个带有蝙蝠侠符号的 sed 示例
【解决方案2】:

在匹配后添加一行。

sed 命令可以在找到模式匹配后添加新行。 sed 的“a”命令告诉它在找到匹配项后添加一个新行。

sed '/unix/ a "添加新行"' file.txt

unix is great os. unix is opensource. unix is free os.

    "Add a new line"
    
    learn operating system.
    
    unixlinux which one you choose.
    
    "Add a new line"

在匹配前添加一行

sed 命令可以在找到模式匹配之前添加一个新行。 sed 的“i”命令告诉它在找到匹配之前添加一个新行。

sed '/unix/ i "添加新行"' file.txt

"Add a new line"

unix is great os. unix is opensource. unix is free os.

learn operating system.

"Add a new line"

unixlinux which one you choose.

【讨论】:

  • 大声笑 - 众所周知,unix 不是开源的。 ;)
【解决方案3】:

以下适用于 Oracle Linux,x8664:

$ echo 'foobar' | sed 's/foo/foo\n/'
foo
bar

如果您需要每行匹配多次,则需要在末尾放置一个g,如下所示:

$ echo 'foobarfoobaz' | sed 's/foo/foo\n/g'
foo
barfoo
baz

【讨论】:

    【解决方案4】:

    在 sed 中获取换行符的可移植方式是反斜杠后跟文字换行符:

    $ echo 'foo' | sed 's/foo/foo\
    bar/'
    foo
    bar
    

    我保证通过使用 awk 而不是 sed 可以更简单地解决您的整个问题。

    【讨论】:

      猜你喜欢
      • 2023-02-06
      • 1970-01-01
      • 1970-01-01
      • 2013-06-26
      • 1970-01-01
      • 2013-03-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多