Bash 使用sed插入换行符(\n)

Bash 使用sed插入换行符(\n),bash,sed,freebsd,Bash,Sed,Freebsd,我正在尝试将一些列表清理到一个正确格式的CSV文件中,以便导入数据库 我的起始文件看起来像这样,每个“行”应该跨越多行,如下所示 Mr. John Doe Exclusively Stuff, 186 Caravelle Drive, Ponte Vedra 33487. 我创建了一个清理文件的sed脚本(有很多“脏”格式,比如双空格和逗号前后的空格)问题在于周期的压缩。我想将该周期更改为新行,但无法使其正常工作 我使用的命令是: sed -E -f scrub.sed test.txt

我正在尝试将一些列表清理到一个正确格式的CSV文件中,以便导入数据库

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

Mr. John Doe
Exclusively Stuff, 186 
Caravelle Drive, Ponte Vedra
33487. 
我创建了一个清理文件的
sed
脚本(有很多“脏”格式,比如双空格和逗号前后的空格)问题在于周期的压缩。我想将该周期更改为新行,但无法使其正常工作

我使用的命令是:

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+(句号)是一个很好的使用替换的“分隔符”,那么虽然我可以找到它,但我似乎无法告诉它在那里放一个换行符

我在网上找到的大多数东西都是关于用其他东西替换换行符(通常是删除它们),但用换行符替换的内容并不多。我确实找到了这个,但它不起作用:

我有什么遗漏吗

更新:

我编辑了我的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  

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

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

我保证使用awk而不是sed可以解决整个问题。BSD上的
sed
不支持新行的
\n
表示(将其转换为文本
n
):

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
或定义新行:

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

nl='
'
BASH/zsh/其他支持:

然后使用带有适当引号和转义符的
sed
插入文字
\n

echo "123." | sed 's/\./'"\\${nl}"'next line/'
123
next line
或者使用
awk

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

或者使用GNU-sed,它支持Oracle Linux x8664上的以下工作:

$ echo 'foobar' | sed 's/foo/foo\n/'
foo
bar
如果需要每行匹配一次以上,则需要在末尾放置一个
g
,如所示:

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

在比赛后添加一行。

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

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

在匹配前添加一行

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

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


这里似乎很好用。使用相同的文件和脚本,我在最后用换行符重新格式化了数据。将
\n\n
放在sed脚本的倒数第二行中,可以得到预期的两行换行符。(然而,我在“Doe”和“exclusive”之间没有逗号)。我在Linux上使用(GNU sed)4.4。您使用的是哪个版本/平台?我知道了,我正在FreeBSDAh上使用
sed
。如果可以的话,可以尝试使用GNU sed?我还看到,我在输出中得到了“FL”,正如您希望从脚本中得到的一样。你确定你提供的输出来自你提供的脚本吗?这是正确的。在试图混淆真实数据时,我无意中删除了FL。考虑不要在邮政编码之后删除换行符。将
s |\n | | g
更改为
s |\([^[:space:]\)\n\([^[:space:]\)\124;\ 1\2 | g
,以便只转换后面带有字符的新行。然后,您不必恢复您没有删除的内容。我正试图在sed脚本中使用转义文字,如图所示,但由于任何原因,它不起作用。但是,re:关于您所说的BSD不支持
\n
,我将改变策略,将
tr
合并到BSD中。我从未想到它不受支持。谢谢我正试图在sed脚本中使用转义文字,如图所示,但无论出于何种原因,它都不起作用。在一个
sed
脚本和一行
sed
脚本中很难做到这一点。您还可以使用多字符分隔符(例如
),然后使用
awk
将其更改为
\n
。老实说,POSIX
sed
最好只用于单行更改。在脚本中添加文字换行并不比在命令行上难-语法不会更改。显然,您永远不会真正插入一个字符或字符串,然后通过管道将其转换为换行符,因为这是不必要的脆弱和低效的。不过,OPs剩下的问题与此无关,对于他提出的问题来说效果很好,而他现在的问题是他的脚本的另一部分(他的循环中的
s|,[[:space:]]|,| g
在添加新行后删除它)。@EdMorton:我想我没有尝试用字面上的新行调试他的脚本。我确实记得(作为一个BSD用户)让我挠头的时候,我觉得它应该工作,但没有。是的,Solaris sed更糟糕。如果它不是简单的
s/old/new/
,那么你就陷入了混乱符文的不同组合中,包括每一个标点符号、单个字母和蝙蝠侠符号,每一个符号的含义都在一个接一个地变化。因此,awk…:-)。lol-unix是众所周知的非开源
$ echo 'foobar' | sed 's/foo/foo\n/'
foo
bar
$ echo 'foobarfoobaz' | sed 's/foo/foo\n/g'
foo
barfoo
baz
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"
"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.