使用 GREP 过滤
Filtering Using GREP
问题就像
找出那些数字大于等于 m 但小于 n 的名字。
给出了一个“.csv”文件。最好使用 grep (regex) 解决此问题。
我要这样走:
cat abc.csv|cut -f 3,7 -d ","|grep "4[4-9][0-9]*"|head
但它给了我想要的东西
注意第3列是人名,第7列是对应的人数
解决此问题的任何建议都会非常有帮助。
尝试:
cut -d, -f 3,7 Bulk.csv | grep ',4[0-9][0-9][^0-9]' | cut -d, -f 1
说明:cat
不需要。表达式 [^0-9]
表示除数字以外的所有内容;仅使用 ,4[0-9][0-9]
作为正则表达式会 select 也包含小数点前有更多数字的行,例如 4247.14
,这不是您想要的。
我们缺少您输入文件的示例 Bulk.csv
来重现您的问题。
如果您只需要名称,则必须添加:
cut -f 1 -d ","
如果您只需要 400.00 到 499.99 之间的实数(正如我从您的结果中看到的那样),那么 grep 应该是:
grep "4[0-9][0-9]\.[0-9][0-9]"
如果您需要接受任意数量的小数和整数,并注意可选的尾随空格和行尾 ($),您可以使用:
grep -E "4[0-9][0-9](\.[0-9][0-9]*)* *$"
如果您需要确定它不匹配 1400 或包含 400 的名称,那么您应该使用:
grep -E " *, *4[0-9][0-9](\.[0-9][0-9]*)* *$"
我们可以继续,但我会在这里停下来。
我的建议是使用这个:
cat Bulk.csv | cut -f 3,7 -d "," | grep -E " *, *4[0-9][0-9](\.[0-9][0-9]*)* *$" | cut -f 1 -d ","
Some people, when confronted with a problem, think "I know,
I'll use regular expressions." Now they have two problems.
(参考https://blog.codinghorror.com/regular-expressions-now-you-have-two-problems/)。
这不是如何使用 grep
的一个很好的例子,因为有据可查的是,使用正则表达式进行数字比较是一种比仅比较数字更困难和脆弱的方法,例如使用 awk
,并且当您的数据在特定字段中时在一行上使用 grep
也比使用理解字段的工具更困难和脆弱,例如再次awk
。
测试字段内容是否在数值范围内的正确方法是仅对该字段进行数值比较:
awk -F, '(440<=) && (<500){print }' abc.csv
我根据您在问题中尝试的正则表达式猜测您希望范围具有的值,如果我猜错了,请更改它们。
我从其他一些答案中看到,您不想打印 </code> 包含 <code>.
的行,或者您可能只想要 </code> 是整数的行。如果是这样,那么使用正则表达式来测试是一件微不足道且适当的事情:</p>
<pre><code>awk -F, '( !~ /\./) && (440<=) && (<500){print }' abc.csv
或:
awk -F, '( ~ /^[0-9]+$/) && (440<=) && (<500){print }' abc.csv
希望您能看到,与尝试使用 grep 跨行对正则表达式进行同样的操作相比,未来的修改是多么清晰、简单、健壮和易于修改。
使用模式打印第 3 列的值,其中第 7 列在 400-499 的范围内,仅 awk
而不是通过多个程序进行管道传输。
模式 ^4[0-9][0-9]$
使用锚 ^
和 $
来防止部分匹配和 2 个范围 0-9 来匹配 400 到 499。
awk -F, '
~ /^4[0-9][0-9]$/ {
print
}
' abc.csv
如果可以使用gnu grep
,则可以匹配第3个字段的值,如果第7个字段在400-499范围内,但它是一个长模式,我建议使用awk。
^(?:[^,]*,){2}\K[^,\n]+(?=(?:,[^,\n]*){3},\s*4[0-9][0-9](?=\s*,|$))
^
字符串开头
(?:[^,]*,){2}
匹配前 2 个逗号分隔的字段
\K
忘记目前匹配的是什么
[^,]+
匹配第3个字段
(?=
正面前瞻断言
(?:,[^,\n]*){3},\s*4[0-9][0-9](?=\s*,|$)
将第 7 个字段匹配为 400-499 之间的值,后跟逗号或字符串结尾以防止部分匹配
)
关闭前瞻
看到一个regex demo
例如
grep -oP "^(?:[^,]*,){2}\K[^,]+(?=(?:,[^,]*){3},\s*4[0-9][0-9](?=\s*,|$))" abc.csv
问题就像 找出那些数字大于等于 m 但小于 n 的名字。 给出了一个“.csv”文件。最好使用 grep (regex) 解决此问题。
我要这样走:
cat abc.csv|cut -f 3,7 -d ","|grep "4[4-9][0-9]*"|head
但它给了我想要的东西
注意第3列是人名,第7列是对应的人数
解决此问题的任何建议都会非常有帮助。
尝试:
cut -d, -f 3,7 Bulk.csv | grep ',4[0-9][0-9][^0-9]' | cut -d, -f 1
说明:cat
不需要。表达式 [^0-9]
表示除数字以外的所有内容;仅使用 ,4[0-9][0-9]
作为正则表达式会 select 也包含小数点前有更多数字的行,例如 4247.14
,这不是您想要的。
我们缺少您输入文件的示例 Bulk.csv
来重现您的问题。
如果您只需要名称,则必须添加:
cut -f 1 -d ","
如果您只需要 400.00 到 499.99 之间的实数(正如我从您的结果中看到的那样),那么 grep 应该是:
grep "4[0-9][0-9]\.[0-9][0-9]"
如果您需要接受任意数量的小数和整数,并注意可选的尾随空格和行尾 ($),您可以使用:
grep -E "4[0-9][0-9](\.[0-9][0-9]*)* *$"
如果您需要确定它不匹配 1400 或包含 400 的名称,那么您应该使用:
grep -E " *, *4[0-9][0-9](\.[0-9][0-9]*)* *$"
我们可以继续,但我会在这里停下来。 我的建议是使用这个:
cat Bulk.csv | cut -f 3,7 -d "," | grep -E " *, *4[0-9][0-9](\.[0-9][0-9]*)* *$" | cut -f 1 -d ","
Some people, when confronted with a problem, think "I know,
I'll use regular expressions." Now they have two problems.
(参考https://blog.codinghorror.com/regular-expressions-now-you-have-two-problems/)。
这不是如何使用 grep
的一个很好的例子,因为有据可查的是,使用正则表达式进行数字比较是一种比仅比较数字更困难和脆弱的方法,例如使用 awk
,并且当您的数据在特定字段中时在一行上使用 grep
也比使用理解字段的工具更困难和脆弱,例如再次awk
。
测试字段内容是否在数值范围内的正确方法是仅对该字段进行数值比较:
awk -F, '(440<=) && (<500){print }' abc.csv
我根据您在问题中尝试的正则表达式猜测您希望范围具有的值,如果我猜错了,请更改它们。
我从其他一些答案中看到,您不想打印 </code> 包含 <code>.
的行,或者您可能只想要 </code> 是整数的行。如果是这样,那么使用正则表达式来测试是一件微不足道且适当的事情:</p>
<pre><code>awk -F, '( !~ /\./) && (440<=) && (<500){print }' abc.csv
或:
awk -F, '( ~ /^[0-9]+$/) && (440<=) && (<500){print }' abc.csv
希望您能看到,与尝试使用 grep 跨行对正则表达式进行同样的操作相比,未来的修改是多么清晰、简单、健壮和易于修改。
使用模式打印第 3 列的值,其中第 7 列在 400-499 的范围内,仅 awk
而不是通过多个程序进行管道传输。
模式 ^4[0-9][0-9]$
使用锚 ^
和 $
来防止部分匹配和 2 个范围 0-9 来匹配 400 到 499。
awk -F, '
~ /^4[0-9][0-9]$/ {
print
}
' abc.csv
如果可以使用gnu grep
,则可以匹配第3个字段的值,如果第7个字段在400-499范围内,但它是一个长模式,我建议使用awk。
^(?:[^,]*,){2}\K[^,\n]+(?=(?:,[^,\n]*){3},\s*4[0-9][0-9](?=\s*,|$))
^
字符串开头(?:[^,]*,){2}
匹配前 2 个逗号分隔的字段\K
忘记目前匹配的是什么[^,]+
匹配第3个字段(?=
正面前瞻断言(?:,[^,\n]*){3},\s*4[0-9][0-9](?=\s*,|$)
将第 7 个字段匹配为 400-499 之间的值,后跟逗号或字符串结尾以防止部分匹配
)
关闭前瞻
看到一个regex demo
例如
grep -oP "^(?:[^,]*,){2}\K[^,]+(?=(?:,[^,]*){3},\s*4[0-9][0-9](?=\s*,|$))" abc.csv