在awk中使用空行作为文件分隔符

3

我需要知道在awk中是否可以使用换行符作为字段分隔符,以将多个行合并成一行?

例如:

$ cat yo  
a aa aaa  
bb bbb bbb  
cccc ccccc cccc  
ddd dddd ddd  
eeeee eeeee eee  

fffff ffffff fffffff  
gggg ggggg  
hhhhhh hhhhhhh hhhhhhhhh  

iii iiiiiiiii iiiii  
jjjj jjjjj jjjjj  
kkkkk kkkkk  
lllllllll lll ll  

以下是我小小脑袋能想到的一些方法,但都没有起作用。
cat file |awk -F'\n' '{print}'    
cat yo |awk 'NF'  '{print $NF}'  


cat yo |awk -F'/^$/d'  '{print $NF}'  
cat yo |awk -F'^$^[ \t]*$' '{print $NF}'  

cat yo |awk -F'^..' '{print $NF}'  

cat yo |awk -F'\t' '{print}'  

期望输出:

a aa aaa  bb bbb bbb cccc ccccc cccc ddd dddd ddd eeeee eeeee eee  
fffff ffffff fffffff gggg ggggg hhhhhh hhhhhhh hhhhhhhhh  
iii iiiiiiiii iiiii jjjj jjjjj jjjjj kkkkk kkkkk lllllllll lll ll  
5个回答

3
您可以将记录分隔符定义为RS=,这将使它以段落为单位:每行是一个字段,每个记录是一个块:
$ awk -v RS= '{for (i=1; i<=NF; i++) printf "%s%s", $i, (i==NF?"\n":" ")}' file
a aa aaa bb bbb bbb cccc ccccc cccc ddd dddd ddd eeeee eeeee eee 
fffff ffffff fffffff gggg ggggg hhhhhh hhhhhhh hhhhhhhhh 
iii iiiiiiiii iiiii jjjj jjjjj jjjjj kkkkk kkkkk lllllllll lll ll

实际上这与以下内容相同:

awk -v RS= '{for (i=1; i<=NF; i++) printf "%s%s", $i, (i==NF?ORS:FS)}' file

啊咳 - awk -v RS= '$1=$1' file - Ed Morton
1
@EdMorton 真的!我几分钟前看到了你的回答,它比我的更出色:)我不知道为什么发现需要“打印”以重新处理内容。现在我看到$1=$1就足够了。棒极了! - fedorqui
1
通常情况下,重新编译$0并打印它的方法是{$1=$1}1,以解决记录为空的情况,但在这种情况下不适用。 - Ed Morton
如果大小很重要,您甚至可以缩短它,例如 awk '$1=$1' RS= file - Jotne
1
通常大小并不重要,正如我可能已经提到过一两次,在文件名列表中设置变量是为了在文件之间更改值,否则在脚本前面使用“-v”设置它们会更清晰、更少出错。 - Ed Morton

3
awk中实现这一点的方法非常简单:
$ awk -v RS= '$1=$1' file
a aa aaa bb bbb bbb cccc ccccc cccc ddd dddd ddd eeeee eeeee eee
fffff ffffff fffffff gggg ggggg hhhhhh hhhhhhh hhhhhhhhh
iii iiiiiiiii iiiii jjjj jjjjj jjjjj kkkkk kkkkk lllllllll lll ll

2
您可能希望重新定义记录分隔符,而不是字段分隔符....
引用自man awk
Records
   Normally, records are separated by newline characters.  You can control 
   how records are separated by assigning values to the built-in variable
   RS.  If RS is any single character, that character separates records.  
   Otherwise, RS is a regular expression.  Text in the input that  matches
   this  regular expression separates the record.  However, in compatibility 
   mode, only the first character of its string value is used for separating 
   records.  If RS is set to the null string, then records are separated by 
   blank lines.  When RS is set to the null string,  the  newline character 
   always acts as a field separator, in addition to whatever value FS may have.

所以尝试这个;
awk 'BEGIN{RS="\n\n";}{print NF;}'

感谢解释。 - user2809888

1
如果您在使用awk时没有使用任何约束,那么可以简单地使用循环,逐行读取来完成:
while read -r line ; do 
  if [[ -z $line ]]; then echo ;  else echo -n $line;  fi 
done <file

这样不会将没有空格的行连接起来吗?最好避免在输出行末尾添加额外的空格。编辑:抱歉,我没有看到输入行以空格结尾。 - konsolebox
不错!另外,[[ -z "$line" ]] && echo || echo -n "$line " 也可以实现。 - fedorqui

1
通过 awk 的 gsub 函数,
$ awk -v RS="" '{gsub(/\n/,"")}1' file
a aa aaa  bb bbb bbb  cccc ccccc cccc  ddd dddd ddd  eeeee eeeee eee  
fffff ffffff fffffff  gggg ggggg  hhhhhh hhhhhhh hhhhhhhhh  
iii iiiiiiiii iiiii  jjjj jjjjj jjjjj  kkkkk kkkkk  lllllllll lll ll 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接