开发者

escape reserved chars from a regexp(sed) parameter

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
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜