使用 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
,但巧合的是,我今天想这样做两次。我查看了手册页,但没有看到任何可以执行此操作的选项。
在匹配模式之后只返回一行的一部分是一个非常相似的问题。也许它甚至是重复的。有人可能会争辩说我的范围更窄一些:可以保证我正在抓取的模式和我正在删除的模式是相同的。我想删除x
. 问题要删除.*x
。
那应该是:
但是这种解析输出的方法
declare -p
是有缺陷的。例如,如果环境中有 a
VAR=$'\ndeclare -- reboot #'
,并且您将该输出提供给 shell 进行解释,该怎么办?另请注意,对于已声明但未分配任何值的变量,将
bash
打印:declare -- VARNAME
,因此在 之后declare reboot
,上述代码也会输出reboot
。您可以将其更改为:
限制为分配的变量,但这仍然不能解决包含换行符的变量的问题(即使仅针对
$TERMCAP
变量也是常见的)。相反,您可以使用这种 hack:
我们在哪里评估
declare -p
我们转义的地方的输出,(
并在数组和关联数组表示中使用,在重新定义为一个函数之后,如果第一个参数是 ,则打印它的第二个参数。使用风险自负,过去已知 bash 的输出对于评估是不安全的,添加转义也可能会增加复杂性,特别是对于它们接受的行长度有限制的实现。)
[
]
declare
--
declare -p
sed
sed
在 中
zsh
,你可以这样做:打印标量变量的定义并且没有任何属性(甚至不是special也不是linked),这似乎是您的意图。
typesetsilent
但是请注意,如果在函数中调用(在这种情况下,它将所有这些变量声明为本地变量)或启用该选项,则它不起作用。另一种可以解决这个问题并让您更好地控制如何引用值的方法是:
q+
给出与 . 使用的引用风格相似的引用风格typeset
。如果您打算在 shell 中使用该输出(可能不是 zsh,或者不是来自同一版本,或者不在相同的语言环境或 OS/libc 中),请使用qq
更安全的引用样式。如果可用,请使用
grep -P
:请注意,您的方法通常不会很好地工作,因为变量可能包含您将切断的换行符
grep
并获得语法错误。参见例如:
A.
sed
和grep
shell 将某些变量的值显示在多行上,因为它们包含嵌入的换行符。
grep
并被sed
设计成在同一行逐行搜索模式(换行符用作硬编码分隔符)。B. 使用
awk
awk 可以选择一行上的模式,但也可以有条件地应用规则。
1.选择匹配的行
declare --
declare
前面两条规则允许 1. 显示没有属性的变量和 2. 多行值在后续行中显示的值。
我们可以使用示例输入来显示模式匹配的概述。
变量的值
HOSTNAME
显示成功是因为两条规则连续匹配:一条规则匹配一行,另一条匹配下一行。但是,我们也看到GREETINGS
变量值被部分显示。实际上,虽然该行不以 pattern 开头,但由于该行(或“记录”)与第二个 rule 匹配,因此会显示declare --
后续行(变量值 cf 的子字符串) 。World!"
!/^declare/
由于多行值是后续的,所以只需要显示一些连续的行。
2.检查shell变量的值
现在介绍用于更好地理解代码复杂性的算法是合适的。
首先,你要知道 Awk 每次读取记录时都会检查所有规则(默认为当前行)。但是,您必须考虑之前完成的处理(在之前的记录中)。换句话说,程序在处理下一行时需要知道它的状态:解析的 shell 变量是什么?为此,我们定义了一个名为 的“布尔”变量
scan
。代码无疑是复杂的。它是相互排斥的条件指令的有序序列(如逻辑 XOR)。有关更多信息,请阅读“为什么代码如此复杂?”部分。
A. 变量没有值
第三个字段如果不包含等号则不是shell变量赋值,它只是一个变量名。
B. 变量有值
变量的值可以包含使用双引号转义的特殊字符。
变量赋值有两种类型:标量变量的声明和数组变量的声明。
无论如何,该值由一对特定字符分隔,要么
"
和"
要么(
和)
。如果相应的分隔符在同一行,则变量的值不包含换行符。否则下一行必须显示到相应的分隔符。开始分隔符位于存储在
beg
变量中的特定位置,而关闭分隔符必须被搜索(使用end
变量)。注意:
match()
是一个内置的 Awk 函数,它返回与模式匹配的子字符串的开始和结束位置(使用预定义的变量RSTART
和RLENGTH
)。这里我们将等号后面beg
的字符和记录的最后一个字符保存在end
.一个。该值不包含嵌入的换行符
字符
beg
和end
是成对的分隔符。如果第二次和第三次测试为假,则表示不扫描下一行。确实,Awk 变量赋值
scan = 0
等价于真值“false”。具体而言,这意味着不显示包含与所选模式(想要的变量)无关的子字符串的行。如果我们以“1.选择匹配的行”部分为例,这允许不显示作为( )
World!"
值的子字符串。GREETINGS
declare -x
湾。该值包含嵌入的换行符
此条件指令指示该值尚未正确定界。因此,定界符必然位于另一行(与当前行连续的后续行)。在这种情况下,
scan = 1
指示扫描下一行,scan
在逻辑测试中变为“真”。严格来说,变量的赋值在
scan
功能0
上没有用,但它提醒读者,默认情况下这个变量设置为0
。事实上,我们在对应if
部分有相同的“序列”,但在这部分变量赋值scan = 0
非常有用(参见“值不包含嵌入的换行符”一节)。C. 显示下一个(下...)行
;; 待定
为什么这段代码如此复杂?
这段代码很复杂,因为它检查了分隔符的各种组合。这并不复杂,但测试是特定的。
awk 程序
您可以使用 Perl 轻松完成:
如果你使用ack,你可以这样做:
输出