使用Perl、sed或awk的一行命令来改变文件格式

4
我可以帮您翻译成中文。这段文字的意思是:我需要关于如何更改文件格式的建议,格式应该像下面这样:file1:。
A       504688
B       jobnameA
A       504690
B       jobnameB
A       504691
B       jobnameC
...

写入到file2中:

A       B
504688  jobnameA
504690  jobnameB
504691  jobnameC
...

一种我能想到的解决方案是:

cat file1 | perl -0777 -p -e 's/\s+B/\t/' | awk '{print $2"\t"$3}'.

但我想知道是否有更有效的方法或已知的做法来完成这项工作。


2
非常感谢,Mat。最近我加入了这个社区。我会去做的。 - Alby
6个回答

7
 perl -nawe 'print "@F[1 .. $#F]", $F[0] eq "A" ? "\t" : "\n"' < /tmp/ab

请在perlrun中查找选项。

另一个有用的选项是-l(添加换行符以打印),但在此情况下不需要。


@briandfoy - 谢谢 - 不过这只是一个一行代码罢了。请放心,我确实读过您的书! :) 而且我强烈推荐它! - Lumi
谢谢您的回答!顺便问一下,末尾的“<”真的需要吗?我没有加它也可以正常工作。它是做什么用的?我只知道“>”用于将输出定向。 - Alby
1
< 是 shell 语法(Bash 和其他 UNIX 系统,以及 cmd.exe/Windows)中用于标准输入 (STDIN) 重定向的操作符。所以在这种情况下,标准输入来自文件。要理解为什么在 Perl 中不需要使用这个输入重定向操作符,可以阅读关于 <ARGV> 文件句柄 的相关内容。 - Lumi
感谢您的详细解释! - Alby

5
假设您的输入文件是以制表符分隔的:
echo $'A\tB'
cut -f2 filename | paste - -

由于这正是cutpaste的设计目的,因此应该很快。


+1 - pastejoin从未真正成为我永久性的心理工具,但这可能是最机器高效的解决方案。用于以空格分隔的文件的变体:cut -b8- /tmp/ab | paste - - - Lumi
哇...这非常优雅。你能解释一下粘贴命令中的选项具体是做什么吗?Cygwin手册似乎不够明确。而且它是否灵活?也就是说,我可以给出更多选项,比如将下面的两行粘贴(转置)? - Alby
1
请参见 http://man.cx/paste -- 'paste' 命令接受文件名作为参数,并连接相应的行。如果将“-”作为文件名,则该文件的行将从标准输入中读取。由于该命令中有 2 条破折号,因此将分别读取“文件1”的一行和“文件2”的另一行,直到所有输入都被消耗完毕。 - glenn jackman
非常整洁,感谢您提供如此清晰明了的解释。 - Alby

2
awk '/^A/{num=$2}/^B/{print num,$2}' file

或者,作为替代方案,
awk '{num=$2;getline;print num,$2}' file

1
这是一个sed解决方案:
sed -e 'N' -e 's/A\s*\(.*\)\nB\s*\(.*\)/\1\t\2/' file

这个版本还会在顶部打印标题:

sed '1{h;s/.*/A\tB/p;g};N;s/A\s*\(.*\)\nB\s*\(.*\)/\1\t\2/' file

或者另一种选择:

sed -n '/^A\s*/{s///;h};/^B\s*/{s///;H;g;s/\n/\t/p}' file

如果您的sed不支持分号作为备选命令的命令分隔符:

sed -n '
/^A\s*/{       # if the line starts with "A"
s///             # remove the "A" and the whitespace
h                # copy the remainder into the hold space
}              # end if
/^B\s*/{       # if the line starts with "B"
s///             # remove the "B" and the whitespace 
H                # append pattern space to hold space
g                # copy hold space to pattern space
s/\n/\t/p        # replace newline with tab and print
}' file

这个版本还会在顶部打印标题:

sed -n '/^A\s*/{s///;h;1s/.*/A\tB/p};/^B\s*/{s///;H;g;s/\n/\t/p}' file

1

这将适用于任何标题文本,而不仅仅是固定的AB >>

awk '{a=$1;b=$2;getline;if(c!=1){print a,$1;c=1};print b,$2}' file1 >file2

...并且它也会打印标题行

如果您需要\t分隔符,请使用:

awk '{a=$1;b=$2;getline;if(c!=1){print a"\t"$1;c=1};print b"\t"$2}' file1 >file2

0
这可能适用于您:
 sed -e '1i\A\tB' -e 'N;s/A\s*\(\S*\).*\nB\s*\(\S*\).*/\1\t\2/' file

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