grep:匹配第一个空格之前(不包括空格)的所有字符

37
我有一个文本文件,它的格式如下:
characters(that I want to keep) (space) characters(that I want to remove)

所以举个例子:

foo garbagetext
hello moregarbage
keepthis removethis
(etc.)

所以我在Linux中尝试使用grep命令,只保留每行中第一个空格之前的字符。我尝试了很多次,比如:
grep '*[[:space:]]' text1.txt > text2.txt
grep '*[^\s]' text1.txt > text2.txt
grep '/^[^[[:space:]]]+/' text1.txt > text2.txt

尝试从不同的示例中拼凑,但是我没有成功。它们都生成了一个空白的text2.txt文件。我对此还很陌生。我做错了什么吗?
*编辑:
我想保留的部分包括大写字母。所以我希望在每一行中保留直到空格之前的任何/所有字符(删除从空格开始的所有内容)。
**编辑:
垃圾文本(我想要删除的)可以包含任何内容,包括空格、特殊字符等。例如:
AA rough, cindery lava [n -S]

在运行grep -o '[^ ]*' text1.txt > text2.txt之后,上面的那一行变成了:
AA
rough,
cindery
lava
[n
-S]

在text2.txt中。(我只想保留的是AA
解决方案(由Rohit Jain提供,beny23进一步提供意见):
grep -o '^[^ ]*' text1.txt > text2.txt
4个回答

53
你把量词 * 放错地方了。
尝试使用这个替代方式:-
grep '^[^\s]*' text1.txt > text2.txt

或者,甚至更好:-
grep '^\S*' text1.txt > text2.txt  

\S 表示匹配非空白字符。而锚点^用于匹配行的开头。


1
这是否包括大写字母?我运行了这两个命令,它们只是生成了相同的文件。我想要删除从空格开始的所有内容(在我给出的示例中保留“foo”、“hello”和“keepthis”)。 - lord_sneed
5
如果不加-o选项,grep命令会打印整行文本,而非只打印匹配的部分。因此,您需要添加-o选项来只显示匹配的部分。请注意,这样做不会改变原意。 - beny23
1
@lord_sneed.. 啊!抱歉,我又忘记放锚点了。使用 grep -o '^[^ ]*' text1.txt > text2.txt 来匹配开头。 - Rohit Jain
我看到这个代码可以运行,但是不确定为什么;查找后发现“^”是行首或字符串起始标记,但在这里似乎表示“非”...是这样吗?方括号代表一个范围...?我想要的是类似的搜索只匹配行的前面部分,所以我将“grep '^[^\s]'”改为“grep '^[^\[]'”,因为我想匹配直到遇到“_开方括号_”。它可以工作,但就像上面说的,我真的不知道为什么。?? - Dee
1
@Dee 是的,这就是原因。当“^”放在字符类的开头时,它会否定整个字符类。当在任何正则表达式的开头使用时,它表示匹配模式应该出现在行的开头。 - Rohit Jain
显示剩余14条评论

18

我知道这个问题早已被grep解决,但是为了后代,我想指出在这种特定情况下至少有另外两种解决方案,它们比grep更高效。

由于您没有进行任何复杂的文本模式匹配,只是取用以空格作为分隔符的第一列,您可以使用一些基于列的工具,如awk或cut。

使用awk

$ awk '{print $1}' text1.txt > text2.txt

使用cut命令

$ cut -f1 -d' ' text1.txt > text2.txt

对大约1.1MB文件进行基准测试

$ time grep -o '^[^ ]*' text1.txt > text2.txt

real    0m0.064s
user    0m0.062s
sys     0m0.001s
$ time awk '{print $1}' text1.txt > text2.txt

real    0m0.021s
user    0m0.017s
sys     0m0.004s
$ time cut -f1 -d' ' text1.txt > text2.txt

real    0m0.007s
user    0m0.004s
sys     0m0.003s

awkgrep 快大约 3 倍,cutawk 快大约 3 倍。虽然对于只运行一次的小文件来说区别不大,但如果你正在编写可重复使用的脚本或经常处理大型文件,你可能会感受到额外的效率提升。


“cut”方法是我最喜欢的。 - Kar.ma

0
我经常使用egrep来帮助“着色”日志行,所以我一直在寻找正则表达式的新变化。对我来说,上面的方法通过添加\W会更好:
$ egrep --color '^\S*\W|bag' /tmp/barf -o
foo
bag
hello
bag
keepthis
(etc.)

问题是,我的日志文件几乎总是有时间戳,所以我在示例文件中添加了一行:
2013-06-11 date stamped line

然后它的效果就不太好了。 所以我又回到了之前的正则表达式:
egrep --color '^\w*\b|bag' /tmp/barf

但是未标日期的行显示出了问题那个。没有上色很难看到这一点...


0

继@Steve的回答之后,如果您想使用不同的分隔符(例如逗号),可以使用-F指定它。如果您想要每行内容直到第一个逗号的内容,比如尝试读取csv文件中第一个字段的值时,这将非常有用。

$ awk -F "," '{print $1}' text1.txt > text2.txt

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