我有这样的输入,该行块由空行分隔,需要将行转换为列
输入
HEAD1
IF
FI
GH
HEAD2
PU
GT
HEAD3
FG
DF
YT
GU
需要这样打印:
HEAD1 IF FI GH
HEAD2 PU GT
HEAD3 FG DF YT GU
答案1
$ awk -v RS='' '{ $1 = $1; print }' file
HEAD1 IF FI GH
HEAD2 PU GT
HEAD3 FG DF YT GU
当RS
输入记录分隔符 为空白而不是默认的换行符时,awk
将根据输入中出现的两个或多个连续换行符将输入划分为记录,即一个或多个空白行将被视为标记结束的一个记录。这通常称为awk
“段落模式”。
然后代码将第一个字段设置为其自身。这看起来像是一个无操作操作,但它会导致awk
重新形成当前的输出记录。使用ORS
(输出记录分隔符)和(输出字段分隔符)的默认值OFS
(分别是换行符和空格符),因此当打印记录时,所有字段都打印在一行上,中间有空格它们以换行符结尾。
您可以通过修改 的值来获取由其他字符串或字符分隔的字段OFS
:
$ awk -v RS='' -v OFS='\t' '{ $1 = $1; print }' file
HEAD1 IF FI GH
HEAD2 PU GT
HEAD3 FG DF YT GU
$ awk -v RS='' -v OFS=',' '{ $1 = $1; print }' file
HEAD1,IF,FI,GH
HEAD2,PU,GT
HEAD3,FG,DF,YT,GU
$ awk -v RS='' -v OFS='::' '{ $1 = $1; print }' file
HEAD1::IF::FI::GH
HEAD2::PU::GT
HEAD3::FG::DF::YT::GU
该awk
代码可以缩短为{ $1 = $1 }; 1
,其中尾随1
将导致通过无条件调用默认操作来打印当前记录。这是无条件打印当前记录的相当常见的方法。
改为使用sed
:
$ sed -e '/./ { H; $!d; }' -e 'x; y/\n/ /; s/.//' file
HEAD1 IF FI GH
HEAD2 PU GT
HEAD3 FG DF YT GU
H
如果该行包含任何内容,这会将当前行附加到保留空间。该行使用定界换行符附加到保留空间。如果这不是最后一行输入,则模式空间将被丢弃d
,并且我们立即从下一行输入开始。
如果当前行为空,我们将保留空间替换为x
(由于模式空间为空,因此也具有清除保留空间的效果),用空格替换所有换行符,并删除第一个字符(这将是一个额外的空格字符)。
答案2
awk
在段落模式下:
awk -v RS= -v FS='\n' -v OFS=' ' '{
for (i=1;i<=NF;i++) {
printf "%s%s", $i, (i<NF ? OFS : ORS)
}
}' file
HEAD1 IF FI GH
HEAD2 PU GT
HEAD3 FG DF YT GU
RS=
这样设置RS
后,输入记录之间用空行分隔。FS='\n'
这样您就可以将每个段落中的每一行视为记录的一个字段。- with
for
我们遍历所有字段,并printf
在条件表达式下打印它们ternary expression
:如果 exp1i<NF
返回 true,OFS
则执行;否则,ORS
将被处决。