我有一些这样的文件:
abc 123
abc 789
bcd 456
acb 135
我想打印当前行下一行的第一列。
期望的输出:
abc 123 abc
abc 789 bcd
bcd 456 acb
acb 135
我更喜欢使用 awk。
答案1
记住上一行:
awk 'NR > 1 { print prev, $1 } { prev = $0 } END { print prev }'
这会按如下方式处理输入:
- 如果当前行是第二行或更大,则打印上一行(存储在 中
prev
,请参阅下一步)和当前行的第一个字段,用输出字段分隔符(默认为空格字符)分隔; - 在所有情况下,将当前行存储在
prev
变量中; - 在文件末尾,打印上一行。
答案2
替代awk
方法:
$ awk 'NR == 1{printf "%s", $0;next}{printf " %s\n%s", $1,$0}' input.txt
abc 123 abc
abc 789 bcd
bcd 456 acb
acb 135
其工作方式很简单:第一行是特殊情况 - 我们打印它而不换行,并告诉 awk 转到下一行而不执行其他代码块。之后,NR == 1{printf "%s", $0;next}
将被跳过,但其他部分会完成该工作。
请记住,到目前为止,我们打印了一个没有换行符的格式化字符串。因此,现在要做的printf " %s\n%s",$1,$0
是打印出第一个单词(并且因为没有换行符,所以它保留在输出的同一行上),插入换行符,然后插入整行本身(但不以换行符终止) 。因此插入的下一个第一个单词将保留在同一行。过程继续进行,直到到达文件末尾。
可能的改进是包括END{print ""}
插入最终换行符的块。在某些情况下,结果文件将由其他脚本处理,这可能是可取的。
虽然用户特别请求 AWK,但其他语言(例如 Python)也可以采用打印格式化字符串的相同方法。为那些好奇如何用其他语言实现这一点的人提供了 Python 替代方案:
#!/usr/bin/env python
from __future__ import print_function
import sys
old = None
for index,line in enumerate(sys.stdin):
if index == 0:
print(line.strip(),end=" ")
continue
words = line.strip().split()
print(words[0] + "\n" + line.strip(),end=" ")
用法如下:
$ ./append_first.py < input.txt
abc 123 abc
abc 789 bcd
bcd 456 acb
acb 135
关于最终换行符的相同想法也适用于此。
答案3
这是一种丑陋的sed
方式只是为了好玩
sed '2,$ s/[^ ]\+/& &/; 2,$ s/ /\n/' file | paste -d ' ' - -
abc 123 abc
abc 789 bcd
bcd 456 acb
acb 135
解释
2,$
从第二行到最后一行s/[^ ]\+/& &/
将第一组非空白字符加倍;
分隔命令,就像在 shell 中一样s/ /\n/
用换行符替换第一个空格paste -d ' ' - -
把这些乱七八糟的东西粘在一起(将第二行附加到第三行,将第四行附加到第三行,等等)
答案4
在我看来,最简单且最易读的方法是:
- 提取第一列 (
cut
) - 从提取的列中删除第一行 (
tail
) - 将此列粘贴到源文件中 (
paste
)
示例:您的示例输入文件:
abc 123
abc 789
bcd 456
acb 135
然后在终端中运行以下命令
cut -d' ' -f1 in.txt | tail -n +2 | paste -d' ' file -
输出:
abc 123 abc
abc 789 bcd
bcd 456 acb
acb 135
该解决方案背后的结构与给出的答案不同。不需要条件、循环或正则表达式。