我的 unix 输出为
ABC : 123
DEFG : 4587
MJk : 36
我想将所有行合并为单行,并具有相同的分隔,例如
ABC DEFG MJK : 123 4587 36
我知道使用 awk 在单列中打印输出,即
awk'{print $1}' | tr '\n' ' '
但正在打印
ABC DEFG MJK
不是值 123 4587 36
答案1
$ awk -F: '{a=a $1; b=b $2} END{print a FS b}' file
ABC DEFG MJk : 123 4587 36
最近我们看到很多帖子,人们使用tr '\n' ' '
或类似的方法将换行符转换为其他内容。除非在极少数情况下,否则不要这样做,因为它将 POSIX 文本文件(所有 POSIX 文本处理工具都可以读取)转换为其他 YMMV 格式的文件。 POSIX 文本行以 结尾\n
,POSIX txt 文件由 POSIX 文本行组成。如果您使用tr
或其他任何方式删除所有换行符,那么任何后续 POSIX 文本处理工具(awk、sed 等)可能会将其作为输入执行未定义的行为。
下面是一些您可能意想不到但实际上是由 POSIX 定义的其他行为的示例。假设我们想要将这个多行字符串转换为单个空格分隔的行:
$ printf 'foo\nbar\n' | wc -l
2
用于tr
删除所有\n
s:
$ printf 'foo\nbar\n' | tr '\n' ' '
foo bar $
$ printf 'foo\nbar\n' | tr '\n' ' ' | wc -l
0
与输出 POSIX 文本文件相同的更好方法相比,因此在通过管道传输到时给出更直观的结果wc
:
$ printf 'foo\nbar\n' | paste -sd ' ' -
foo bar
$ printf 'foo\nbar\n' | paste -sd ' ' - | wc -l
1
答案2
这可以使用 sed 编辑器通过将下一行附加到 tge 模式空间并在中心冒号周围打乱字段来完成。测试命令循环直到 eof 并在每次迭代中选择下一行。
sed -Ee '
:a;$!N;s/(.*):(.*)\n(.*):(.*)/\1\3:\2\4/;ta
' file
awk 版本是不言自明的。
awk -F ':' -v ORS='' '
{ a[NR] = $1; b[NR] = $2 }
END {
a[NR] = a[NR] FS
for (i=1; i<=2*NR; i++)
print i<=NR ? a[i] : b[i-NR]
print RS
}
' file
结果:
ABC DEFG MJK : 123 4587 36
答案3
看来您需要缓冲整个内容。您可以尝试以下操作:
awk '{FNR==1{first=$1; second=$3} FNR>1{first=first " " $1; second=second " " $3} END{printf("%s : %s\n", first, second)}'
这将累积变量中所有行的所有“第一列条目”的内容first
,以及变量中“第二列条目”的内容(实际上是第三列,因为从s 的角度来看,它将:
形成自己的一列)。awk
多变的second
。最后,它打印如此累积的缓冲区,并使用:
分隔符作为分隔符。
如果前导/尾随空格不是问题,您可以将代码缩短为
awk '{first=first " " $1; second=second " " $3} END{printf("%s : %s\n", first, second)}'
答案4
我宁愿将每一列存储在一个数组中,然后以所需的格式打印它们
awk -F" : " '{a[NR]=$1;b[NR]=$2} END{ for(i=1;i<=NR;i++) printf "%s ",a[i]; printf ": "; for(i=1;i<=NR;i++) printf "%s ",b[i];}' file
-F" : "
根据" : "
分隔符分隔列{a[NR]=$1;b[NR]=$2}
创建两个数组indexes =NR
(行数)和values =该行中列的值printf
按所需顺序打印(printf
不会打印 anewline
)