我需要在文件中用方括号替换变量:
a=0
foo[1]=0
foo[2]=0
我想替换foo[1]=0
为foo[1]=2
。
要更改a
我使用的值:
func_update_value () {
field=$1
newvalue=$2
sed -i "s/^\($field=\).*/\1$newvalue/" file
}
field="a"
value="2"
func_update_value $field $value
但相同的命令不适用于foo[x]
...
func_update_value () {
field=$1
newvalue=$2
sed -i "s/^\($field=\).*/\1$newvalue/" file
}
n=1
field="foo[$n]"
value="2"
func_update_value $field $value
正确的语法是sed
什么?
更改是通过功能进行的,是否可以在sed
两种情况下都使用单个命令?
[1]
在外壳程序中不是(即不一定)字面量。然后,它不是(当然不是)作为regex模式的一部分的文字sed
。
我已经检查过您以前的问题,并且我猜您正在使用Bash。我的答案的第一部分适用于许多常见的shell,包括Bash(zsh是一个明显的例外)。
首先,您将值分配给变量:
n=1
field="foo[$n]"
value="2"
所有这一切都如您所愿。1
不带引号的不是特别的,它不需要被引号。所引用的内容2
可能会或可能不会被引用,这没有任何区别。周围的双引号foo[$n]
会有所不同;好的是,它们在那里,以这种方式[
并且]
没有什么特别的,并且field
变量的内容从字面上是foo[1]
可以肯定的。
但是你有
func_update_value $field $value
这里$field
没有加引号。在参数扩展之后,该行是
func_update_value foo[1] 2
然后开始对当前目录中的对象进行模式匹配(globbing),尤其是:
[…]
匹配其中任何一个字符。
这意味着如果您有一个名为的文件或目录foo1
,则该行的计算结果为
func_update_value foo1 2
如果您设置n=125
并且目录中有foo1
and foo5
(和/或foo2
),那就更糟了。一个以上的文件将匹配该foo[125]
模式,该行的最终形式将是
func_update_value foo1 foo5 2
这绝对不是您想要的。您可能foo1
在当前目录中没有任何名称,因此该模式在此刻保持原样,并且该行
func_update_value foo[1] 2
func_update_value
使用文字参数foo[1]
和来运行函数2
。
如果此时您的代码没有失败,则仅是由于没有foo1
进入目录的缘故,而不是因为编码正确。正确的编码包括对所有变量加双引号。如果您知道自己在做什么,那么在极少数情况下,您不想报价。这不是其中的一个。
另请注意,函数本身field=$1
中$1
没有引用位置。使用unquoted的问题与之前使用unquoted的问题$1
相同$field
。
sed
假设您的函数正确获取了文字foo[1]
参数,并且其局部field
变量现在包含了foo[1]
应有的文字字符串。
问题是[1]
因为sed
不是文字的正则表达式模式的一部分。像在外壳程序中一样,它匹配任何一个封闭的字符(匹配的对象是文本,而不是文件名)。foo[125]
会匹配foo1
或foo2
或foo5
。仅foo[1]
匹配foo1
。
要进行sed
匹配[
,]
从字面上看,您需要在模式中将其转义。而不是field="foo[$n]"
你需要
field="foo\[$n\]"
sed
两种情况下都可以使用单个命令吗?
是的。您当前的指令就像sed "s/^\($field=\).*/\1$newvalue/"
只要你牢记的价值,将工作$field
将被解释为模式(这样的一部分[
,.
,\(
,$
等特殊)和值$newvalue
将被解释为的一部分替换(因此\1
很特殊)。您选择的分隔符(/
)不能出现在两个变量中的任何一个中,否则它将破坏或更改语法。
单独使用第二个修订(在[
和之前添加反斜杠]
)甚至可以防止shell扩展[…]
,因此在这种特定情况下,对于变量的此特定值,它会意外地“修复”引用问题。
通常,尽管您应该同时应用这两个修复程序。并且您当然应该习惯于默认情况下引用变量,这将在调试未来的Shell脚本时节省您的时间和精力。这就是为什么我的答案不只限于第二种解决方法。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句