I want to write a script that modifies a variable in a .properties file. The user enters the new value which is in turn written into the file.
read -p "Input Variable?" newVar
sed -r 开发者_如何转开发's/^\s*myvar=.*/myvar=${newVar}/' ./config.properties
Unfortunately problems arise when the user inputs special characters. In my use case it is very likely that a "/" character is typed. So my guess is that I have to parse ${newVar} for all slashes and escape them? But how? Is there a better way?
have a look at bash printf
%q quote the argument in a way that can be reused as shell input
Example:
$ printf "%q" "input with special characters // \\ / \ $ # @"
input\ with\ special\ characters\ //\ \\\ /\ \\\ \$\ #\ @
Avoiding shell quoting is a good general principle.
#! /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;
}
Substitution with s///
as above will be familiar to sed
users.
The code above uses Perl's in-place editing facility (enabled most commonly with the -i
switch but above with the special $^I
variable) to modify files named on the command line and create backups with the .bak
extension.
Example usage:
$ 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
Edit: oops, we are only qoting the value, not the regex. So this is what you need
You are better off using perl
instead of sed
for this if it is available.
read -p "Input Variable?" newVar
perl -i -p -e 'BEGIN{$val=shift;}' \
-e 's/^\s*myvar=.*/myvar=$val/' \
"$newVar" ./config.properties
Edit2: Sorry, still does not handle \ characters in newVar. Guess one of the other solutions is better. As stated before, dealing with shell escaping is your issue.
You are better off using a tool that understands variables -- Perl, maybe AWK -- trying to quote a random string so that you avoid all unintended interactions with sed command parsing is asking for trouble.
Also, you won't get your variable interpolated when using single quotes, and even with -r
, sed does not grok Perl regex syntax -- -r
only gets you to the egrep
version of regexes, so \s
doesn't do what you want.
Anyway, ignoring my own advice, here's how we'd do it in the old days before we had those better tools:
read -p "Input Variable?" newVar
sed "/^ *myvar=/c\\
myvar=`echo \"$newVar\" | sed 's/\\\\/\\\\\\\\/'`" ./config.properties
If you don't think your users will figure out how to input literal backslashes at your prompt, you can simplify this to:
read -p "Input Variable?" newVar
sed "/^ *myvar=/c\\
myvar=$newVar" ./config.properties
精彩评论