我在一个文件中有 2 个变量,如下所示,我需要分配一个由一个用户输入插入的新值: read -p "Enter CName Name : " CName
sid=C02SBX
SID=C02SBX
当我运行以下 GNUsed
语句时:
sed -i "s/sid=.*/sid=$CName/gI" dbca2.rsp
它将更新变量如下:
sid=C03SBX
sid=C03SBX
问题:我如何确保标志sid
前的第二个=
始终保持大写,例如SID=C03SBX
第一个sid
保持小写。另外,无论用户输入小写还是大写,符号后面的sid
和都应始终为大写,例如 ( )?SID
=
=C03SBX
答案1
通常,您不应该嵌入数据在里面代码语言解释器的参数,无论它们是 shell、sed
、awk
、perl
、python
等。
这样做总是会引入命令注入漏洞。
所以像, sed -e "code $data"
, sh -c "code $data"
, eval "code $data"
(注意双倍的应该从词汇表中perl -e "code $data"
$var
删除其中的 s 扩展为 shell 变量的内容的引号。
数据应该通过用于数据而不是代码的通道传递。sed
(与sh
、awk
以及任何现代或不太现代的编程语言相反)没有这样的通道,因此唯一的选择是清理这些数据,但sed
自 80 年代以来,又出现了更好的替代方案。
在这里,您可以使用:
perl -pi -s -e 's/\bsid=\K.*/\U$value/i' -- -value="$CName" -- "$file"
请注意 code 参数是如何固定的:s/\bsid=\K.*/\U$value/i
,并且数据(shell 变量的内容$CName
)作为单独的非代码参数传递,旨在传递值(通过分配给$value
perl 变量)。
另请注意:
-i
(复制自perl
)是 中的非标准选项sed
。I
命令的标志也是如此sed
。- 不需要,
g
因为将.*
匹配到行尾,因此每行只能有一个替换。s/\bsid=\K\S*/\U$value/gi
当我们匹配sid=
后跟任意数量的非空白字符时,它可能是有意义的,然后它会sid=foo SID=bar
在一行上更改为sid=new-value SID=new-value
。 perl
(与将输入解释为在用户区域设置中编码的文本相反sed
)默认情况下将每个字节视为一个字符,因此如果文件包含在用户区域设置中不形成有效字符的字节,它仍然可以正常工作。\U
(来自 ex/vi)将后面的内容转换为大写。请注意,默认情况下,它仅适用于 ASCII 字母。某些实现也支持,sed
但不是全部,也不是标准的。或者,您可以让 shelltypeset -u CName
在 ksh/zsh 中使用该值将值转换为大写,或者$CName:u
在 tcsh/zsh 或${(U)CName}
zsh 或${CName^^}
bash 中使用。这些通常会解释区域设置编码中的文本,并根据区域设置规则更改大小写。例如,i
可以更改为I
或İ
取决于语言环境,并且İ
可以将其编码为 0xdd 字节或字节 0xc4 0xb0,具体取决于语言环境是使用 iso8859-9 还是 UTF-8 作为字符映射。- 注意
\b
对于词b
边界sid=foo
,因此它与setsid=foo
例如不匹配。某些实现也支持,sed
而其他一些实现则用\<
/\>
(来自 ex/vi)或[[:<:]]
/[[:>:]]
代替。 \K
K
指定比赛中 ept的开始。对于旧版本的perl
,您可以使用s/(sid=).*/$1\U$value/i
,即捕获sid=
带括号的部分并在替换时调用它$1
。或者使用后视操作符,s/(?<=sid=).*/\U$value/i
但在我看来,它看起来有点太复杂了。-s
作为with的替代方案-var=value
,您可以使用环境变量来传递数据:VALUE=$CName perl -pi -e 's/\bsid=\K.*/\U$ENV{VALUE}/i' -- "$file"
。如果该值是敏感的并且不应在 的输出中暴露ps -Af
,那么这将是更好的选择。这也是您在awk
(那里)使用的方法,ENVIRON["VALUE"]
因为其他值传递通道会破坏包含反斜杠的数据。- 要从用户读取任意字符串,语法为
bash
(IFS= read -rp 'Prompt: ' var
在IFS= read -r 'var?Prompt: '
其他类似 Korn 的 shell 中)。但提示用户通常不是最好的方法,因为它会使您的脚本更加难以自动化或使用相同的参数重用。通常最好将输入作为命令行参数,例如you-script thenewCN
参数可用的位置$1
,或者使用标准getopts
内置命令进行正确的标准命令行解析。
答案2
使用分组\(...\)
和引用(\1
对于第一组、\2
第二组等):
sed -i "s/\(sid=\).*/\1${CName^^}/gI" dbca2.rsp
为了将用户输入转换为大写,使用 shell:${var^^}
答案3
您可以不区分大小写地匹配要替换的行,但仅修改以 开头的部分=
,而不是整行:
sed -e "/^[Ss][Ii][Dd]=/s/=*/=${^^CName}/"
请注意,${^^…}
要大写参数是Bash 功能,不是标准的 POSIX shell 结构。