从 grep 的输出中删除匹配模式?

从 grep 的输出中删除匹配模式?

使用 bash,我运行以下命令:declare -p | grep 'declare -- '这将打印整行。我想打印相同的行,但我想排除匹配本身。即,我可以将其... | grep pattern | sed 's/pattern//'作为单个命令执行吗?这就像选项的反面-o

我的命令输出如下:

...
declare -- MAX_CONNECTIONS_PER_SERVER="6"
declare -- OPTERR="1"
declare -- OSTYPE="linux-gnu"
...

但我想输出这个:

...
MAX_CONNECTIONS_PER_SERVER="6"
OPTERR="1"
OSTYPE="linux-gnu"
...

通常,我只会将其通过管道传递给sed,但巧合的是,我今天想这样做两次。我查看了手册页,但没有看到任何可以执行此操作的选项。

仅返回匹配模式之后的行部分是一个非常相似的问题。也许它甚至是重复的。有人可能会说我的有点窄:它保证我正在 grep 的模式和我正在删除的模式将是相同的。我想删除x.问题想删除.*x

答案1

那应该只是:

declare -p | sed -n 's/^declare -- //p'

但这种解析输出的方法declare -p是有缺陷的。

VAR=$'\ndeclare -- reboot #'例如,如果环境中有一个,并且您将该输出提供给 shell 进行解释怎么办?

另请注意,对于已声明但未分配任何值的变量,bash会打印:declare -- VARNAME,因此在 之后declare reboot,上面的代码也会输出reboot

你可以将其更改为:

declare -p | LC_ALL=C sed -n 's/^declare -- \(.*=\)/\1/p'

限制分配的变量,但这仍然不能解决包含换行符的变量的问题(即使仅对于变量来说,这也是常见的$TERMCAP)。

相反,你可以使用这种黑客:

(
  export LC_ALL=C
  eval '
    declare()
      if [[ $1 = -- ]]; then
        printf "%s=%q\n" "${2%%=*}" "${2#*=}"
      fi'"
    $(declare -p | sed 's/[][()]/\\&/g')"
)

declare -p在重新定义为一个函数(如果第一个参数是 则打印第二个参数)之后,我们评估在数组和关联数组表示中使用的转义()[的输出。使用风险自负,过去 bash 的输出被认为是不安全的,添加转义也可能会增加复杂性,特别是对于接受的行长度有限制的实现。]declare--declare -psedsed


在 中zsh,你可以这样做:

typeset ${(k)parameters[(R)scalar]}

打印变量的定义标量并且没有任何属性(甚至没有特别的也不捆绑)这似乎是你的意图。

typesetsilent但请注意,如果在函数内调用(在这种情况下它将把所有这些变量声明为本地变量)或者启用该选项,则它不起作用。

另一种可以解决这个问题并让您更好地控制值的引用方式的方法是:

() for 1 do print -r -- $1=${(Pq+)1}; done ${(k)parameters[(R)scalar]}

q+给出与 所使用的类似的引用样式typeset。用于qq更安全的引用风格如果您打算在 shell 中使用该输出(可能不是 zsh,或者不是来自同一版本,或者不在同一语言环境或 OS/libc 中)。

答案2

如果可用,请使用grep -P

declare -p | grep -Po 'declare -- \K.*'

请注意,您的方法通常不会很好地工作,因为变量可能包含换行符,您将用它来切断grep并出现语法错误。

参见例如:

declare -- IFS="    
"

答案3

您可以使用 Perl 轻松完成:

declare -p | perl -lne'/^declare -- (.*)/ && print $1'

如果你使用确认, 你可以这样做:

declare -p | ack '^declare -- (.*)' --output='$1'

答案4

declare -p |awk -F "--" '/declare --/{print $NF}'

输出

 MAX_CONNECTIONS_PER_SERVER="6"
 OPTERR="1"
 OSTYPE="linux-gnu"

相关内容