Regex 替换/替换shell脚本中的敌对子字符串变量

Regex 替换/替换shell脚本中的敌对子字符串变量,regex,bash,shell,Regex,Bash,Shell,我有三个未替换的对抗性shell变量 $mystring $old $new 记住,这三个字符串都是对立的。它们将包含特殊字符。它们将包含所有可能会弄乱系统的东西。如果替换中存在漏洞,字符串将利用它 在$mystring中用$new替换$old最简单的函数是什么? 我在堆栈溢出中找不到任何通用替换的解决方案,这种替换在所有情况下都有效。这里没有什么特别之处-要确保您的值在a中被视为文本,您需要做的唯一一件事是确保您引用的是搜索值,如以下相关部分所述: 如果内部没有双引号,$old将被解释为fn

我有三个未替换的对抗性shell变量

$mystring
$old
$new
记住,这三个字符串都是对立的。它们将包含特殊字符。它们将包含所有可能会弄乱系统的东西。如果替换中存在漏洞,字符串将利用它

在$mystring中用$new替换$old最简单的函数是什么?
我在堆栈溢出中找不到任何通用替换的解决方案,这种替换在所有情况下都有效。

这里没有什么特别之处-要确保您的值在a中被视为文本,您需要做的唯一一件事是确保您引用的是搜索值,如以下相关部分所述:

如果内部没有双引号,$old将被解释为fnmatch样式的glob表达式;对他们来说,这是字面意义上的

在流上操作,而考虑GSUBI文字,也在BasHFAQ 21中描述:

# usage: gsub_literal STR REP
# replaces all instances of STR with REP. reads from stdin and writes to stdout.
gsub_literal() {
  # STR cannot be empty
  [[ $1 ]] || return

  # string manip needed to escape '\'s, so awk doesn't expand '\n' and such
  awk -v str="${1//\\/\\\\}" -v rep="${2//\\/\\\\}" '
    # get the length of the search string
    BEGIN {
      len = length(str);
    }

    {
      # empty the output string
      out = "";

      # continue looping while the search string is in the line
      while (i = index($0, str)) {
        # append everything up to the search string, and the replacement string
        out = out substr($0, 1, i-1) rep;

        # remove everything up to and including the first instance of the
        # search string from the line
        $0 = substr($0, i + len);
      }

      # append whatever is left
      out = out $0;

      print out;
    }
  '
}

some_command | gsub_literal "$search" "$rep"
…还可以使用以下技术对文件进行就地替换,这些技术同样取自先前链接的常见问题解答:

# Using GNU tools to preseve ownership/group/permissions
gsub_literal "$search" "$rep" < "$file" > tmp &&
  chown --reference="$file" tmp &&
  chmod --reference="$file" tmp &&
  mv -- tmp "$file"

这里没有什么特别之处-要确保您的值在a中被视为文本,您需要做的唯一一件事是确保您引用的是搜索值,如以下相关部分所述:

如果内部没有双引号,$old将被解释为fnmatch样式的glob表达式;对他们来说,这是字面意义上的

在流上操作,而考虑GSUBI文字,也在BasHFAQ 21中描述:

# usage: gsub_literal STR REP
# replaces all instances of STR with REP. reads from stdin and writes to stdout.
gsub_literal() {
  # STR cannot be empty
  [[ $1 ]] || return

  # string manip needed to escape '\'s, so awk doesn't expand '\n' and such
  awk -v str="${1//\\/\\\\}" -v rep="${2//\\/\\\\}" '
    # get the length of the search string
    BEGIN {
      len = length(str);
    }

    {
      # empty the output string
      out = "";

      # continue looping while the search string is in the line
      while (i = index($0, str)) {
        # append everything up to the search string, and the replacement string
        out = out substr($0, 1, i-1) rep;

        # remove everything up to and including the first instance of the
        # search string from the line
        $0 = substr($0, i + len);
      }

      # append whatever is left
      out = out $0;

      print out;
    }
  '
}

some_command | gsub_literal "$search" "$rep"
…还可以使用以下技术对文件进行就地替换,这些技术同样取自先前链接的常见问题解答:

# Using GNU tools to preseve ownership/group/permissions
gsub_literal "$search" "$rep" < "$file" > tmp &&
  chown --reference="$file" tmp &&
  chmod --reference="$file" tmp &&
  mv -- tmp "$file"

当您使用诸如sed之类的工具时,防止对抗性示例是一个问题,这些工具可以在频带内相互传递数据和代码。一旦您避免了这种模式,通过将指令和数据放在带外,数据所包含的细节就变得毫无意义了。或者几乎没有实际意义-许多可用的工具都是面向行的,这就是为什么我没有建议使用'gsub_literal',或者in=$search out=$replace perl-pi-e's/\Q$ENV{in}/$ENV{out}/g'./*来自同一源代码的示例…尽管这些工具仍然做了正确的事情,并将代码和数据彼此隔离开来,最坏的情况是当跨越线边界时无法匹配的字符串,而不是注入攻击。当您使用诸如sed之类的工具在频带内相互传递数据和代码时,如何防止对抗性示例是一个问题。一旦您避免了这种模式,通过将指令和数据放在带外,数据所包含的细节就变得毫无意义了。或者几乎没有实际意义-许多可用的工具都是面向行的,这就是为什么我没有建议使用'gsub_literal',或者in=$search out=$replace perl-pi-e's/\Q$ENV{in}/$ENV{out}/g'./*来自同一源代码的示例…尽管这些工具仍然做了正确的事情,并将代码和数据彼此隔离开来,最糟糕的情况是,当跨越行边界时,字符串无法匹配,而不是注入攻击。如果通用搜索和替换这么简单,我很好奇为什么sed通常被推荐为普通搜索和替换的解决方案,当分隔符出现在字符串中时可能出错?Cargo cult编程——人们在不理解其背后的原因的情况下复制他们在其他地方看到的实践——在shell中很普遍:常见的和最佳实践之间的差异可能更大,sed在大数据流上运行时具有相当好的吞吐量;您不希望在内容为兆字节的变量上使用此答案中的代码。如果您需要具有良好批量性能的健壮性,那么我将使用BashFAQ 21中给出的其他方法之一—awk支持的gsub_literal函数;Perl,内容通过环境变量传递到带外;等等,@hrs,…不过要清楚一点——虽然sed具有更好的吞吐量,因为它是一个外部工具,调用它需要大量的启动成本;因此,如果您一次处理数千行内容,那么每行调用一次sed将非常缓慢,而这里采用的参数扩展方法避免了启动成本。您可以让一个循环更高效地读取单个sed调用的输出,但您不想编写反复调用sed的代码。如果通用搜索和替换就是这么简单,我很好奇为什么sed通常被推荐为普通搜索和替换的解决方案,当分隔符出现在字符串中时可能出错?Cargo cult编程——人们在不理解其背后的原因的情况下复制他们在其他地方看到的实践——在shell中很普遍:常见的和最佳实践之间的差异可能更大,sed在网络上运行时具有相当好的吞吐量
大流量;您不希望在内容为兆字节的变量上使用此答案中的代码。如果您需要具有良好批量性能的健壮性,那么我将使用BashFAQ 21中给出的其他方法之一—awk支持的gsub_literal函数;Perl,内容通过环境变量传递到带外;等等,@hrs,…不过要清楚一点——虽然sed具有更好的吞吐量,因为它是一个外部工具,调用它需要大量的启动成本;因此,如果您一次处理数千行内容,那么每行调用一次sed将非常缓慢,而这里采用的参数扩展方法避免了启动成本。您可以让循环更有效地读取sed的单个调用的输出,但您不希望编写反复调用sed的代码。