【问题标题】:Find exact word from a line and delete that line with grep/sed从一行中找到确切的单词并使用 grep/sed 删除该行
【发布时间】:2016-05-14 09:47:00
【问题描述】:

我在 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,我的函数将返回AllenZhouXiaoyuZhou。做了小研究后,把grep命令参数改成

if $( echo $entry | grep --quiet ^$name:$)

事实证明,它从来没有为AllenZhouXiaoyuZhou 找到任何东西——我很困惑。

sed  -i -n /$name/d $fileName

这是我用来删除包含字符串模式的行的代码。问题就像 grep 一样,如果我输入 ZhouAllen,该命令将删除包含关键字的两行。但是当我改为

sed  -i -n /\<$name\>/d $fileName

它不会删除 AllenZhouXiaoyuZhouZhou... 我再次感到困惑。

【问题讨论】:

  • 请根据您的示例输入显示您的预期输出(编辑您的 Q)。 AND 指示哪个搜索目标。也许您将不得不使用 sed '/AllenZhou/d' 。谢谢,祝你好运。
  • sed -i -n /pattern/d 将删除您的文件 - 可能不是您想要的!
  • google shell 引用约定很快,因为您需要在默认情况下引用您的变量,并且只有在您有特定目的并完全理解所有含义的情况下才不要引用它们。如果你不开始引用你的变量,你很快就会看到一些奇怪的、危险的影响。

标签: bash shell sed grep command


【解决方案1】:

if 中使用命令替换并不是你想的那样。您正在捕获来自grep 的输出——使用-q 选项将始终为空字符串——并将that 作为参数传递给if,它需要一个命令名称或pipeline 作为它的论据。它基本上会尝试执行空字符串,这当然不会做任何有用的事情(最终结果是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" 在第一个冒号之前的任意位置查找匹配项。

您的数据中没有单词边界(空格、标点符号等),只是大小写不同,因此\&lt;\&gt; 无法匹配这些名称。观察你的大写模式,也许你想在匹配后要求一个大写字符或一个冒号; "^[^:]*$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 脚本从任何匹配行打印第二个字段设置结果代码,因此您可以在ifwhile 条件中使用它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-06-26
    • 1970-01-01
    • 2020-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-13
    • 1970-01-01
    相关资源
    最近更新 更多