我想编写一个脚本来修改.properties文件中的变量。用户输入新值,然后将其写入文件。
read -p "Input Variable?" newVar
sed -r 's/^\s*myvar=.*/myvar=${newVar}/' ./config.properties
很不幸,当用户输入特殊字符时会出现问题。在我的使用情况下,很可能输入"/"字符。所以我猜想我需要解析${newVar}中的所有斜杠并对其进行转义?但是如何操作呢?是否有更好的方法?
看一下bash中的printf
%q quote the argument in a way that can be reused as shell input
例子:
$ printf "%q" "input with special characters // \\ / \ $ # @"
input\ with\ special\ characters\ //\ \\\ /\ \\\ \$\ #\ @
避免使用Shell引用是一个很好的通用原则。
#! /usr/bin/env perl
use strict;
use warnings;
die "Usage: $0 properties-file ..\n" unless @ARGV;
print "New value for myvar?\n";
chomp(my $new = <STDIN>);
$^I = ".bak";
while (<>) {
s/^(\s*myvar\s*=\s*).*$/$1$new/;
print;
}
使用上述的 s///
替换将会对 sed
用户来说非常熟悉。
上面的代码使用了 Perl 的原地编辑功能(通常使用 -i
开关启用,但上面使用了特殊的 $^I
变量),以修改命令行中指定的文件,并创建带有 .bak
扩展名的备份。
示例用法:
$ cat foo.properties theirvar=123 myvar=FIXME $ ./prog foo.properties New value for myvar? foo\bar $ cat foo.properties theirvar=123 myvar=foo\bar $ cat foo.properties.bak theirvar=123 myvar=FIXME
最好使用理解变量的工具,比如Perl或AWK,试图引用随机字符串以避免与sed命令解析产生意外交互是在自找麻烦。
此外,使用单引号时无法插入变量,即使使用了-r
,sed也无法理解Perl正则表达式语法---r
只能让你使用egrep
版本的正则表达式,所以\s
不能实现你想要的效果。
总之,忽略我的建议,以下是我们在没有这些更好的工具之前的做法:
read -p "Input Variable?" newVar
sed "/^ *myvar=/c\\
myvar=`echo \"$newVar\" | sed 's/\\\\/\\\\\\\\/'`" ./config.properties
如果您认为用户无法在提示符处输入文字反斜杠,您可以简化如下:
read -p "Input Variable?" newVar
sed "/^ *myvar=/c\\
myvar=$newVar" ./config.properties
编辑:哎呀,我们只引用值,而不是正则表达式。所以这就是你需要的。
如果可以使用,最好使用perl
而不是sed
。
read -p "Input Variable?" newVar
perl -i -p -e 'BEGIN{$val=shift;}' \
-e 's/^\s*myvar=.*/myvar=$val/' \
"$newVar" ./config.properties
编辑2:抱歉,仍然无法处理newVar中的\字符。猜测其他解决方案更好。如前所述,处理shell转义是您的问题。
$newVar
之前就剥离掉\字符。除了编写自定义shell循环外,我不知道有什么方法可以输出/传递包含\字符的shell变量。即使在上面的示例中,两个\字符中的一个也已经丢失了。这确实是一个棘手的问题。有人能解决吗? - Sodved