awk:打印所有内容,但不打印最后的第n列

awk:打印所有内容,但不打印最后的第n列,awk,Awk,我有一个这样的输入文件: foo bar 08 320984 2384 bla foo baz 23 32425 32532 [...] 最后总是有三个令牌,但前面的令牌数量未知。我想将文件重写为CSV,以便其他应用程序可以自动解析它。我当前的awk命令是: awk '{ print $(NF-2)";"$(NF-1)";"$NF}' 输出应该是 foo bar;08;320984;2384 bla foo baz;23;32425;32532 [...] 如果我正确理解你和fedorqu

我有一个这样的输入文件:

foo bar 08 320984 2384
bla foo baz 23 32425 32532
[...]
最后总是有三个令牌,但前面的令牌数量未知。我想将文件重写为CSV,以便其他应用程序可以自动解析它。我当前的awk命令是:

awk '{ print $(NF-2)";"$(NF-1)";"$NF}'
输出应该是

foo bar;08;320984;2384
bla foo baz;23;32425;32532
[...]

如果我正确理解你和fedorqui:

awk '{for (i=1;i<NF;i++) printf "%s%s",$i,(i+4>NF?";":FS);print $NF}' file
foo bar;08;320984;2384
bla foo baz;23;32425;32532
awk'{for(i=1;iNF?”;“:FS);打印$NF}”文件
富吧;08;320984;2384
布拉富巴兹;23;32425;32532
这将添加
位于最后三个字段前面


可能是更好的方法。

如果我正确理解你和fedorqui:

awk '{for (i=1;i<NF;i++) printf "%s%s",$i,(i+4>NF?";":FS);print $NF}' file
foo bar;08;320984;2384
bla foo baz;23;32425;32532
awk'{for(i=1;iNF?”;“:FS);打印$NF}”文件
富吧;08;320984;2384
布拉富巴兹;23;32425;32532
这将添加
位于最后三个字段前面


这可能是更好的方法。

不幸的是,awk并不是最擅长的(而且
cut
的字段范围处理能力在这里也没有帮助

不过,类似的方法应该可以奏效:

awk '{nfff=$(NF-2); nff=$(NF-1); nf=$NF; NF-=3; printf "%s;%s;%s;%s\n", $0, nfff, nff, nf}' file

不幸的是,awk并不是最好的(而且
cut
的字段范围处理能力在这里也没有帮助

不过,类似的方法应该可以奏效:

awk '{nfff=$(NF-2); nff=$(NF-1); nf=$NF; NF-=3; printf "%s;%s;%s;%s\n", $0, nfff, nff, nf}' file

sed
也可以工作:

sed 's/\ \([^\ ]\+\)\ \([^\ ]\+\)\ \([^\ ]\+\)$/;\1;\2;\3/' file
或者如果您的
sed
支持
-r

sed -r 's/\ ([^\ ]+)\ ([^\ ]+)\ ([^\ ]+)$/;\1;\2;\3/' file
它用
替换最后3个换行符

或者更容易一点:

rev file | sed 's/\ /;/g; s/;/\ /g4' | rev

sed
也可以工作:

sed 's/\ \([^\ ]\+\)\ \([^\ ]\+\)\ \([^\ ]\+\)$/;\1;\2;\3/' file
或者如果您的
sed
支持
-r

sed -r 's/\ ([^\ ]+)\ ([^\ ]+)\ ([^\ ]+)$/;\1;\2;\3/' file
它用
替换最后3个换行符

或者更容易一点:

rev file | sed 's/\ /;/g; s/;/\ /g4' | rev

一种奇特的GNU awk方法:

gawk '
    function replace(what) {
        return gensub(/[[:blank:]]+([^[:blank:]]+)$/, ";\\1", 1, what)
    }
    {$0 = replace(replace(replace($0))); print}
' file

一种奇特的GNU awk方法:

gawk '
    function replace(what) {
        return gensub(/[[:blank:]]+([^[:blank:]]+)$/, ";\\1", 1, what)
    }
    {$0 = replace(replace(replace($0))); print}
' file

对于最后三个字段之前的任意数量的字段,应执行此操作:

awk '{for (i=1; i <= NF - 3; i++) if (i == 1) printf $i; else printf " "$i} {print ";"$(NF-2)";"$(NF-1)";"$NF}' input

awk'{for(i=1;i这应该适用于最后三个字段之前的任意数量的字段:

awk '{for (i=1; i <= NF - 3; i++) if (i == 1) printf $i; else printf " "$i} {print ";"$(NF-2)";"$(NF-1)";"$NF}' input

<代码> AWK { for(i=1;i)我对AWK是新的,但这如何(这不会删除空白空间):< /P>
<代码> AWK { for(i=0;i)我对AWK是新的,但这如何(这不会删除空白空间):< /P>
awk'{for(i=0;这不是
CSV
,但这不是重点。您正在尝试将文件拆分为四个输出字段?其中最后三个字段是输入的最后三个字段,第一个字段是行中的所有其他字段?您如何知道什么是标记?任何没有数字的文本?一行中有两个单词,一行中有三个单词“最后总是有三个记号,但前面的记号数目不详”这句话的大意是我知道它总是像
tk1 tk2 tk3…tkn tk1 tk2 tk3
一样,必须变成
tk1 tk2 tk3…tkn;tk1;tk2;tk3
@fedorqui所以简而言之,为最后三个字段中的每一个添加
。@Jotne在前面,准确地说。这不是
CSV
,但这不是重点。你正试图将文件拆分为到四个输出字段?其中最后三个字段是输入的最后三个字段,第一个字段是行中的所有其他字段?您如何知道什么是标记?任何没有数字的文本?一行有两个单词,另一行有三个单词。@Jotne“最后总是有三个代币,但前面的代币数量未知“我知道它总是像
tk1 tk2 tk3…tkn tk1 tk2 tk3
,必须变成
tk1 tk2 tk3…tkn;tk1;tk2;tk3
@fedorqui所以简而言之,为最后三个字段中的每一个添加
。@Jotne在前面。方法上的一个小变化:
$awk'{last=“;”;“$(NF-2)”;“$(NF-1)”;”$NF;NF-=3;print$0 last}'文件
方法上的一个小变化:
$awk'{last=“;”$(NF-2)”;“$(NF-1)”;“$NF;NF-=3;print$0 last}”文件