我在 Ubuntu 20.04 中使用 Bash。
我有文件:
Hello hi 123
if a equals b
you
one abc two three four
dany uri four 123
我需要找到sed
只有-只有4个单词的行。这是我写的代码,它不起作用,它准确地打印了文件。
sed "/[a-Z0-9+]{4}/g" F1
答案1
这确实应该通过一个可以轻松计算字段的工具来解决,例如awk
:
$ awk 'NF == 4' file
if a equals b
dany uri four 123
这使用了NF
一个特殊变量,awk
它将保存当前记录中的字段数。默认情况下,一条记录是一行,字段是由一个或多个空白字符(制表符或空格)分隔的任何子字符串,不包括行开头或结尾的空字段。上面的短awk
程序将输出恰好包含四个字段的任何行。
使用 时sed
,您需要匹配空白分隔的子字符串。
请注意,sed
默认情况下使用基本正则表达式,并且您显示的表达式使用{4}
,它是扩展正则表达式修饰符。基本正则表达式中的等效内容将被编写\{4\}
。您还使用了无效的字符范围 ,a-Z
并且您打算使用的字符类最好写为[[:alnum:]]
,即与任何字母数字字符匹配的内容(假设包含+
是拼写错误)。尾随g
命令(从“保留空间”获取数据)似乎放错了地方。
我在这里的总体想法是将每个单词(一个或多个非空白字符的运行)压缩为单个x
单词,然后删除所有空白字符(制表符或空格)。如果结果字符串恰好是xxxx
,则打印原始行(否则删除该行并立即开始下一个循环)。
sed -e h \
-e 's/[^[:blank:]]\{1,\}/x/g' \
-e 's/[^x]//g' \
-e '/^xxxx$/!d' \
-e g file
这里,原始行首先用 保存到“保留空间” h
,然后如果需要打印,则再次取出,g
最后用 。如果d
执行倒数第二行的命令,则g
永远不会考虑最后一行。
或者,使用扩展正则表达式:
sed -E -e h \
-e 's/[^[:blank:]]+/x/g' \
-e 's/[^x]//g' \
-e '/^xxxx$/!d' \
-e g file
测试:
$ sed -e h \
> -e 's/[^[:blank:]]\{1,\}/x/g' \
> -e 's/[^x]//g' \
> -e '/^xxxx$/!d' \
> -e g file
if a equals b
dany uri four 123
[[:alnum:]]
如果您希望单词字符由类而不是[^[:blank:]]
(非空白)定义,则将上面的表达式更改[^[:blank:]]
为。[[:alnum:]]
不同之处在于,诸如GNU/Linux
或 之类的字符串Unix-system
将被视为两个单词,而不是每个单词。
答案2
使用 GNU sed
:
$ sed -E '/^\s*(\w+\s+){3}\w+\s*$/!d' infile
if a equals b
dany uri four 123
POSIXly;你可以写:
sed '/^[[:space:]]*\([_[:alnum:]][_[:alnum:]]*[[:space:]][[:space:]]*\)\{3\}[_[:alnum:]][_[:alnum:]]*[[:space:]]*$/!d' infile
答案3
利用GNU sed
我们创建的正则表达式,它查看可选的前导空格,后跟正好 4 对非空白+空白,后跟模式空间的结尾。
$ sed -nE 'G;/^\s*(\S+\s+){4}$/P' F1
或者,
sed -nE '
s/\S+/&/4;T # 3 or less chunks
s//&/5;t # 5 or more chunks
p # exactly 4 chunks
' F1
sed -E '
s/\S+/&/5; td # 5 or more chunks
s//&/4; t # exactly 4 chunks
:d;d # 3 or less or 5 or more
' F1
答案4
显然awk
对于这个用例来说这是更好的工具——但是OP指定了sed
。
使用 GNUsed
可以实现多种解决方案。这是使用保留空间的一个:
$ cat -A file
Hello hi 123$
if a equals b$
you$
one abc two three four$
dany uri four 123$
one two three four$
five six ^Iseven eight $
$ sed -e 'h; s/^\s*//; s/\s*$//' -nre '/^\w+(\W+\w+){3}$/{g;p}' file
if a equals b
dany uri four 123
one two three four
five six seven eight
$
该sed
命令可以简化为:
$ sed -nr '/^\s*(\w+)(\W+\w+){3}\s*$/p' file
这是上一个sed
命令的另一个更可移植的版本,它使用 POSIX 字符类 和-E
而不是-r
:
$ sed -En '/^[[:blank:]]*[[:alnum:]]+([[:blank:]]+[[:alnum:]]+){3}[[:blank:]]*$/p' file