如何在Linux中删除文件的最后一列


25

我想删除txt文件的最后一列,但我不知道列号是什么。我该怎么办?

例:

输入:

1223 1234 1323 ... 2222 123
1233 1234 1233 ... 3444 125
0000 5553 3455 ... 2334 222

我希望我的输出是:

1223 1234 1323 ... 2222
1233 1234 1233 ... 3444
0000 5553 3455 ... 2334

有很多方法可以做到this..please添加其中一个例子,你的预期输出..
heemayl

@heemayl ok,我做到了
zara

谢谢..是列选项卡分隔还是空格分隔?
heemayl 2015年

@heemayl空间是决定因素
zara

Answers:


43

awk

awk 'NF{NF-=1};1' <in >out

要么:

awk 'NF{NF--};1' <in >out

要么:

awk 'NF{--NF};1' <in >out

尽管这看起来像伏都教,但它确实有效。这些awk命令每个都有三个部分。

第一个是NF,这是第二部分的前提。NF是一个变量,包含一行中的字段数。在AWK中,如果它们不是0或为空string,则为true ""。因此,第二部分(NF递减的位置)仅在NF不为0 时发生。

第二部分(NF-=1 NF----NF)只是从NF变量中减去一个。这样可以防止最后一个字段被打印,因为更改字段时(在这种情况下,请删除最后一个字段),请awk重新构造$0,默认情况下将所有用空格分隔的字段连接起来。$0不再包含最后一个字段。

最后一部分是1。它不是神奇的,只是用作表示的表达式true。如果awk表达式在没有任何关联操作的awk情况下计算为true,则默认操作为print $0


@JJoao:啊,谢谢,忘了--。注释,当前,您需要;1兼容POSIX。
cuonglm

我最初的意图是使用for循环,但这更加简洁明了。
Sergiy Kolodyazhnyy 2015年

5
值得注意的是,如果您使用的是非默认分隔符,则需要进行一些更改。假设,是您的分隔符:awk -F',' 'BEGIN { OFS = FS }; NF { NF -= 1 }; 1' < in > out
拉玛先生

1
降低NF的效果是POSIX的未定义行为-根据运行的awk,您将获得不同的输出。有些awk会根据需要删除最后一个字段,有些则根本不执行任何操作,而另一些可能会报告语法错误或其他任何原因。
Ed Morton

16

grep与PCRE一起使用:

$ grep -Po '.*(?=\s+[^\s]+$)' file.txt 
1223 1234 1323 ... 2222
1233 1234 1233 ... 3444
0000 5553 3455 ... 2334

使用GNU sed

$ sed -r 's/(.*)\s+[^\s]+$/\1/' file.txt 
1223 1234 1323 ... 2222
1233 1234 1233 ... 3444
0000 5553 3455 ... 2334

1
@ramin Sure ..请问作为一个新问题(这是该网站的工作方式):)
heemayl 2015年

@ramin它会给您任何时间限制或警告吗?
heemayl

它说这是超出标准的问题!
zara 2015年

@ramin Ok ..让我联系管理员,也许他们可以为您提供帮助。.btw您是否检查过有关您问题的旧质量检查?它的可能性问题已经被提出和回答..
heemayl

3
不要问“ 如何在Linux中重命名文件名 ”之类的超级基本问题。使用谷歌。
ChristofferHammarström,2015年

11

使用Perl:

perl -lane '$,=" ";pop(@F);print(@F)' in

使用rev+ cut

rev in | cut -d ' ' -f 2- | rev

5

使用GNU sed:

sed -r 's/\s+\S+$//' input.txt

更一般而言,此代码可与OSX中的BSD sed以及GNU sed一起使用:

sed 's/[[:space:]]\{1,\}[^[:space:]]\{1,\}$//' input.txt

1

如果定界符始终是单个字符(因此两个或多个连续定界符指定为空字段),则可以head仅从输入文件的第一行开始,计算定界符(n定界符表示字段数为n+1),然后用于cut1st字段打印直到n第th个字段(倒数第二个),例如使用制表符分隔的输入:

n=$(head -n 1 infile | tr -dc \\t | tr \\t \\n | wc -l)
cut -f1-$n infile > outfile

或例如与一个csv文件:

n=$(head -n 1 infile | tr -dc , | tr , \\n | wc -l)
cut -d, -f1-$n infile > outfile

如果有时间,我将在以后运行一些基准测试,但是投入大量精力,我认为该解决方案应该比其他使用regex的解决方案更快,因为此解决方案在第一行进行最少的处理即可获得否。字段,然后使用cut为该工作优化的字段。


1

可移植地,您可以使用以下任何一种:

sed 's/[[:space:]]*[^[:space:]]*$//' file

awk '{sub(/[[:space:]]*[^[:space:]]*$/,"")}1' file

0

使用vim:

在vim中打开文件

vim <filename> 

如果光标放置在其他任何地方,请转到第一行。

gg

创建一个名为“Q”的宏qq,即转到当前行的后面$,然后返回到最后空间F(大写F,其次是字面上的空格),然后从当前位置通过行尾删除D再往下一行j和使用停止宏录制q

qq$F Djq

现在,我们可以@q为每行重复宏。
我们还可以按一下@@以重复上一个宏,甚至更简单:

99@q

将宏重复99次。
注意:数字不能完全匹配行。


0

对于有类似问题但使用不同字段分隔符的人,此awk方法将正确保留字段分隔符:

$ cat file 
foo.bar.baz
baz.bar.foo
$ awk -F'.' 'sub(FS $NF,x)' file
foo.bar
baz.bar
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.