将多行输出转换为单行

时间:2013-03-02 17:03:46

标签: sed awk

我管理着一台装有40台ubuntu机器的计算机实验室,我拼凑了这个命令,找到学生主目录中大于100M的文件的总磁盘使用量:

for i in `cat ./lab-machines.txt ` ; do ssh $i "nohup find /home -size +100M -print0 | du --files0-from=- -ch | tail -1 && hostname && ls /home" ; done > lab-disk-usage.txt

文件“lab-machines.txt”包含每个单独行上的计算机的主机名。该命令从已使用无密码登录配置的服务器运行到root用户的实验室计算机。 lab-disk-usage.txt文件中的输出包含每个机器的类似内容(我在括号中插入了注释):

69G total    
hostname
student-username (changes)
admin-username (always the same)
lost+found (always the same)

我希望每台机器的输出看起来像这样:

  

69G主机名学生用户名

我对文本过滤不够熟悉,无法及时完成。你能帮忙吗?

5 个答案:

答案 0 :(得分:1)

试试这个:

awk -vORS=" " 'NR==1{sub("total","")}NR<=3' file

答案 1 :(得分:1)

我稍微修改了您的示例数据:

69G total    
host1
jane
admin-username
lost+found
65G total    
host2
albert
admin-username
lost+found

这可以变成一个表格:

[ghoti@pc ~/tmp]$ awk 'NR%5==1{size=$1} NR%5==2{host=$1} NR%5==3{user=$1; printf("%-8s%-16s%s\n", size, host, user)}' lab-disk-usage.txt
69G     host1           jane
65G     host2           albert

她最重要的是我们使用模运算符(NR%5)来确定每组五行中的位置。

如果您不能依赖每组五行,那么请说明您的输入数据的结构。我们可以通过其他方式检测记录边界,例如查找/[0-9]+G total$/,如果无法使用NR%5

[ghoti@pc ~/tmp]$ awk '/G total$/{size=$1; getline host; getline user; printf("%-8s%-16s%s\n", size, host, user)}' lab-disk-usage.txt 
69G     host1           jane
65G     host2           albert

这基本上只是potong的 GNU sed 建议的awk版本,它也可以是可移植的(即不仅仅是GNU sed):

[ghoti@pc ~/tmp]$ sed -ne '/G total/{s/ .*//;N;N;s/\n/  /g;p;}' lab-disk-usage.txt 
69G  host1  jane
65G  host2  albert

答案 2 :(得分:1)

通过tr命令

输出管道

您可以尝试更简单的解决方案,例如通过 tr 命令管道输出。例如:

tr -s "\n" ' ' < lab-disk-usage.txt

这假设文件中只有一条记录。如果您计划拥有多条记录,则需要先将每条记录通过 tr 管道过滤,然后再将其附加到输出文件中。例如:

your_pipeline_commands | tr -s "\n" ' ' > lab-disk-usage.txt

使用Perl的触发器操作符

如果您有一组多行记录,则需要更加聪明。与AWK相比,Perl在处理多线记录方面具有一些优势,包括触发器操作器。例如:

perl -ne 'if ( /total/../^lost/ ) {
              chomp $_; print $_ . " "
          } else {
              print "\n"
          };
          END { print "\n" };' lab-disk-usage.txt

根据您的实际语料库,您可能需要稍微调整一下正则表达式才能使事情正常运行,但在我的系统上它做的是正确的。

测试Perl的语料库

69G total
hostname
student-username
admin-username
lost+found

69G total
hostname
student-username
admin-username
lost+found

Perl的样本输出

69G total     hostname student-username admin-username lost+found 
69G total     hostname student-username admin-username lost+found 

答案 3 :(得分:0)

这可能适合你(GNU sed):

sed -nr '/ total/{N;N;s/( total\s*)?\n/ /gp}' file

答案 4 :(得分:0)

如果记录之间没有空行,您可以先引入一行:

awk '/total/{print x}1' | awk '{print $1,$3,$4}' RS= OFS='\t' 

使用文件内容:

69G total    
host1
jane
admin-username
lost+found
65G total    
host2
albert
admin-username
lost+found

这会产生:

69G host1   jane
65G host2   albert

如果记录之间已经有空行,您可以在管道之前跳过该部分并使用:

awk '{print $1,$3,$4}' RS= OFS='\t' file