这是我要转换的文件:
john doe
555-666-333
[email protected]
die
jane doe
Beverly Hills
444-333-111
[email protected]
die
我希望结果文件是这样的:
john doe,555-666-333,[email protected]
jane doe,Beverly Hills,444-333-111,[email protected]
该单词die
在文件中,我想用它来分隔我的行,这样它们就不会出现在输出中,如上所示。
编辑
我已经更改了文件的格式。前一种格式没有考虑到单词之间的数量可能会变化的事实die
。
答案1
$ awk -v OFS=',' '/^die$/ { print substr(lines,2); lines=""; next } { lines=lines OFS $0 }' file
john doe,555-666-333,[email protected]
jane doe,Beverly Hills,444-333-111,[email protected]
对于包含逗号的数据,同样的情况也适用(请参阅下面我的答案的末尾)。如果数据包含逗号,您可能需要使用:
awk -v OFS=',' '
/^die$/ { print substr(lines,2); lines=""; next }
/,/ { $0=sprintf("\"%s\"", $0 ) }
{ lines=lines OFS $0 }' file
该代码构建了一个由(逗号)lines
分隔的字符串。当在一行中找到OFS
该单词本身时,输出字符串 in 。当记录的第一个字段附加到字符串时,调用会删除添加在行前面的逗号。带逗号的行的处理方式与我下面的代码相同。die
lines
substr()
使用 GNUawk
或mawk
,但不使用 BSD awk
,你也可以这样做
mawk -v RS='\ndie\n' -v FS='\n' -v ORS='\n' -v OFS=',' '{$1=$1;print}' file
这不会为包含逗号的数据生成带引号的字段。
强制在输出之前根据(输出字段分隔符)和(输出记录分隔符)变量$1=$1
重新形成awk
记录。OFS
ORS
在更新问题之前回答:
paste -d, - - - - <file
这会产生
john doe,555-666-333,[email protected],die
jane doe,444-333-111,[email protected],die
要删除这些die
行(这些是完全没有必要的):
paste -d, - - - - <file | cut -d, -f 1-3
如果原始数据不包含逗号,则上述方法有效。
您还可以die
从头开始过滤掉行:
sed '/^die$/d' file | paste -d, - - -
即使原始数据包含逗号,这也可以工作。
如果数据包含逗号,您可能需要对其进行预处理以在这些行周围添加引号:
awk '/^die$/ { next } /,/ { $0=sprintf("\"%s\"", $0 ) } 1' file | paste -d, - - -
给定文件
john doe
555-666-333
[email protected]
die
jane doe
444-333-111
[email protected]
die
Me, myself and I
000-000-000
[email protected]
最后一个命令会生成
john doe,555-666-333,[email protected]
jane doe,444-333-111,[email protected]
"Me, myself and I",000-000-000,[email protected]
答案2
你可以用这样的惯用语来做到这一点awk
:
$ awk '$1=$1' RS='.die\n' OFS="," FS='\n' file1
john doe,555-666-333,[email protected]
jane doe,Beverly Hills,444-333-111,[email protected]
在上面awk
,我们将记录分隔符定义RS
为die
在文件中用于分隔人员详细信息的条目。
$1=$1
强制 awk 使用“,”作为输出字段分隔符重新计算和打印输入字段OFS
PS:当我怀疑文件结尾有问题时,就像\r
我用来调用tr
删除可能的\r
字符一样:tr -d '\r' file1 |awk .....
顺便说一下,你也可以像这样使用 sed:
$ sed -z 's/\n/,/g; s/,die,/\n/g'
通过欺骗 sed 使用空字符作为记录分隔符,这将产生与 awk 相同的输出。
一旦输入文件中不存在真正的空字符,sed 就会将整个输入文件视为一条大记录 == 一条大行。
答案3
这可以使用“sed”编辑器以 POSIX 方式完成
sed -e '
:a
$q;N;y/\n/,/
s/,die$//;t
ba
' input_file
方法:
- 设置一个循环并将下一行附加到模式空间中。
- 氮命令
- 将换行符更改为逗号,然后尝试去掉“,die”
- 是/// s///命令
- 如果成功,则一切都已准备就绪,无需对此进行进一步处理。
- t没有标签的命令
- 否则,回去获取更多,以防万一我们结束了,我们就退出。
- b 和 q 命令。
我们还可以使用 Perl 来实现此目的:
perl -lne '
push @A, $_ unless /^die$/;
print join ",", splice @A if /^die$/ || eof;
' input_file
我们在数组中累积行,直到看到“骰子”行。此时我们通过逗号连接数组内容(也清空数组)。
我们还可以读取文件,然后调用 Perl 来获取结果:
perl -lF'/^die\n/m' -0777nae 'print join ",", split /\n/ for @F' input_file
- -F'/^die\n/m' 将在正则表达式 BOL die 上将文件拆分为字符串,后跟换行符。
- -0777 将打开吸吮声。-n应禁用自动打印行和-A将根据-F价值。