使用任何东西作为sed或Perl正则表达式的输入?

时间:2018-04-12 12:58:35

标签: linux bash perl sed

如果我这样做

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?

2 个答案:

答案 0 :(得分:5)

当然,使用bash参数替换来逃避麻烦的斜杠字符:

comment () { sed -i "/${1//\//\\/}/ s/^/${2//\//\\/} /" "$3"; }

注意:

  • 您需要保护图案和更换部件中的斜线。
  • 如果你的搜索被锚定,使用“g”是没有意义的,因为模式最多可以匹配一次。
  • 引用所有变量:如果文件名包含空格,则代码会中断。
  • 一行函数在结束括号之前需要分号。

演示

$ 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,任意文件名(包括那些包含空格或以-开头的文件名)。