如果我这样做
comment () { sed -i "/$1/s/^/$2 /g" $3 }
comment /dev/sysmsg '#' /tmp/1
comment '*.err' '#' /tmp/1
带输入文件
*.err;kern.notice;auth.notice /dev/sysmsg
fff
ff
然后它会中断,因为/
在sed
中用作分隔符,而*
也被视为正则表达式。
问题
有没有办法让它健壮,所以$1
中的输入字符串可以包含我想要的任何内容?或者我需要转移到Perl?
答案 0 :(得分:5)
当然,使用bash参数替换来逃避麻烦的斜杠字符:
comment () { sed -i "/${1//\//\\/}/ s/^/${2//\//\\/} /" "$3"; }
注意:
演示
$ cat file
test/1/
test/2/
test/3/
$ comment 'test/2' '//' file
$ cat file
test/1/
// test/2/
test/3/
我意识到我并没有逃避正则表达式的特殊字符。最安全的方法是转义任何非字母数字字符:
comment () {
local pattern=$(sed 's/[^[:alnum:]]/\\&/g' <<<"$1")
local replace=${2//\//\\/}
local file=$3
sed -i "/$pattern/ s/^/$replace /" "$file"
}
但是既然你想进行纯文本匹配,那么sed可能不是最好的工具:
comment() {
perl -i -pse '$_ = "$leader $_" if index($_, $search) > -1' -- \
-search="$1" \
-leader="$2" \
"$3"
}
答案 1 :(得分:2)
最好避免从shell脚本生成代码。
let doors = ["door1", "door2"]
function selectDoor(){
const randomDoor = doors[Math.round(Math.random())]
console.log(randomDoor);
return randomDoor;
}
if(selectDoor() === "door1"){
console.log('you win')
} else {
console.log('you lose')
}
或
comment () {
perl -i -pe'BEGIN { ($s,$r)=splice(@ARGV,0,2) } $_ = "$r $_" if /\Q$s/' -- "$@"
}
或
comment () {
s="$1" r="$2" perl -i -pe'$_ = "$ENV{r} $_" if /\Q$ENV{s}/' -- "$3"
}
支持:
搜索字符串的任意文本(包括通常在正则表达式模式中特殊的字符,例如comment () {
perl -i -spe'$_ = "$r $_" if /\Q$s/' -- -s="$1" -r="$2" -- "$3"
}
)。这是通过使用quotemeta
(作为*
)将文本转换为与该文本匹配的正则表达式模式来实现的。
由于正确引用和使用\Q
,任意文件名(包括那些包含空格或以-
开头的文件名)。