我在Stack Overflow上搜索了一些问题和答案,但它们都不适用于我的情况,我也不知道为什么我的正则表达式不起作用。如果你能指出我错误的想法,我真的很感激。
测试用例:文本文件包含
AllenZhou:9175186661:111th 1111 NY, 11111
XiaoyuZhou:9175186662:2222 222th 22222 NY 22222
Allen:1231231234:abc rd, PA
这是我的功能:
checkEntry(){
vaildName=true
while read entry
do
if $( echo $entry | grep --quiet $name)//$name read from keyboard
then
vaildName=false
fi
done < $fileName
}
如果我输入Zhou
,我的函数将同时返回AllenZhou
和XiaoyuZhou
。在我做了小型研究之后,我将grep命令参数更改为
if $( echo $entry | grep --quiet ^$name:$)
事实证明它永远找不到AllenZhou
或XiaoyuZhou
的任何内容 - 我很困惑。
sed -i -n /$name/d $fileName
这是我用来删除包含字符串模式的行的代码。问题与grep类似,如果我键入Zhou
或Allen
,该命令将删除包含关键字的两行。但是当我改为
sed -i -n /\<$name\>/d $fileName
它不会删除AllenZhou
或XiaoyuZhou
或Zhou
...再次让我感到困惑。
答案 0 :(得分:2)
在if
中使用命令替换不符合您的想法。您正在捕获grep
的输出 - 其中-q
选项始终为空字符串 - 并将 作为参数传递给if
,它希望命令名称或管道作为其参数。它基本上试图执行空字符串,当然它没有做任何有用的事情(净效果是if
条件将总是成功)。
你只想
if echo "$entry" | grep -q "$name"; then
: stuff
fi
或更具惯用性和效率
if [[ "$entry" = *"$name"* ]]; then
: stuff
fi
甚至
case $entry in *"$name"*)
: stuff;;
esac
(双方括号[[
... ]]
仅限Bash,而case
可移植到任何POSIX shell,甚至可移植到原始Bourne shell。单方括号将也是可移植的,他们可以做...... 这样的东西,但它比你想要的更丑,更脆,更复杂。)
还要注意引用。包含任意字符串needs to be quoted的变量。
另外,您希望使用read -r
- 没有选项,read
的行为会带来令人讨厌的遗留行为,以便在某些极端情况下实现历史向后兼容性。
然而,分别检查每一行只是麻烦。整个功能可能是
grep -q "$name" "$fileName"
也返回实际结果;你的函数无法做的事情(除非设置一个全局变量,如果它正在做什么 - 很难从上下文中分辨出来。即使在shell脚本中,在函数中使用全局变量也是一个坏主意)。
也许你想要一些正则表达式锚定来限制与第一个字段的匹配。 grep "^[^:]*$name"
在第一个冒号之前的任何地方查找匹配项。
您的数据中没有单词边界(空格,标点符号等),只是大小写的变化,因此\<
或\>
无法匹配这些名称。观察你的大写模式,也许你想在比赛后要求大写字母或冒号; "^[^:]*$name[[:upper:]:]"
?
如果最终目标是提取地址或电话号码,请直接执行此操作。您需要Awk而不是grep
。
awk -F : -v name="$name" 'BEGIN { pat = name "($|[[:upper:]])"; result = 1 }
$1 ~ pat ( print $2; result = 0 }
END { exit result }' "$fileName"
Awk脚本打印来自任何匹配行的第二个字段,设置结果代码,因此您可以在if
或while
条件下使用它。