【问题标题】:Shell: sed - replace a text from specific number rangeShell:sed - 替换特定数字范围内的文本
【发布时间】:2015-11-09 20:24:09
【问题描述】:

我有以下问题:

sed -e "s/[theText] [someNumber]/$var2/"

文本旁边有一个数字。 我需要执行以下操作 - 如果数字在 5 到 20 之间,请将字符串替换为 $var2,否则什么也不做。有没有可能在不使用循环的情况下直接在 sed 中执行此操作?我尝试过像 theText [5-20]2 这样的结构,但它没有用。谢谢!

【问题讨论】:

    标签: regex bash shell replace sed


    【解决方案1】:

    因为 sed 不懂算术,所以 sed 不是这里的理想工具。但是,以下内容将满足您的要求:

    sed -Ee "s/some text ([5-9]|1[0-9]|20)$/$var2/"
    

    或者,如果您想坚持基本的正则表达式:

    sed -e "s/some text \([5-9]\|1[0-9]\|20\)$/$var2/"
    

    上面查找文本,后跟一个空格,然后是[5-9]1[0-9]20 之一,然后是行尾$

    由于 sed 不懂数学,因此无法指定像 5-20 这样的数字范围。

    请确保您信任 var2 的来源。将$var2 放入这样的 sed 命令是一个安全问题,因为它可以执行任意命令。

    【讨论】:

    • 感谢您的回答。你一般建议做什么?因为区间是动态的(我使用变量作为第一个数字,5-20 只是为了说明)。可能是 1-20 甚至 18-20。我虽然关于使用循环(重复 20 - N 次,在每次迭代中替换范围内的数字之一)。注意:不要关心安全性,它是一个仅供内部使用的脚本:)
    • @melonsvk awk 可能是解决此问题的正确工具:它可以进行替换并且理解数学。
    • 值得注意的是,BSD sed 中的 -E 标志等同于 GNU sed 中的 -r 标志。
    • @miken32 是的。但请注意,现代版本的 GNU sed 支持 -E 作为 -r 的同义词。此外,有传言称-E 将成为 POSIX 的选择。
    【解决方案2】:

    awk 来救援!

    $ awk '{match($0,/some text ([0-9]*)/,a); 
            if(a[1]+0>5 && a[1]+0<20) 
                sub(/some text/,"replacement")}1' << EOF
    > some text 100
    > some text 10
    > EOF
    

    将打印

    some text 100
    replacement 10
    

    【讨论】:

      【解决方案3】:

      我开始拆分字符串和数字,但解决方案变得一团糟:

      lower=4
      upper=88
      matchstring="MyText"
      
      echo "Example testing substring MyText followed by number 4 until 88"
      read -p "Give your teststring "  str
      if [[ ${str} = ^${matchstring}* ]]; then
          echo "Nope, no match with ${matchstring}"
      else
          echo "Matching ${str#${matchstring}}"
          if [[ "${str#${matchstring}}" =~ ^[0-9]+$ ]]; then
             echo "it is a number..."
             if [ ${str#${matchstring}} -ge ${lower} ] &&
                [ ${str#${matchstring}} -le ${upper} ]; then
                echo "Bingo !"
             else
                echo "Not in range (${lower},${upper})"
             fi
          else
             echo "No number"
          fi
      fi
      

      但是这个脚本可以通过结合前两个测试来改进:

      lower=4
      upper=88
      matchstring="MyText"
      
      echo "Example testing substring MyText followed by number 4 until 88"
      read -p "Give your teststring "  str
      if [[ ${str} =~ ^${matchstring}[0-9]+$ ]]; then
          echo "Nope, You should use ${matchstring}123"
      else
          if [ ${str#${matchstring}} -ge ${lower} ] &&
             [ ${str#${matchstring}} -le ${upper} ]; then
             echo "Bingo !"
          else
             echo "Not in range (${lower},${upper})"
          fi
      fi
      

      我仍然不喜欢它的主要原因是它很难阅读。
      您可以引入一个额外的变量 theNumber=${str#${matchstring}},以便在您针对限制测试 theNumber 时更容易阅读。

      【讨论】:

        【解决方案4】:

        您可以使用Bashgrep 来获取数字部分并在使用sed 进行替换之前对其进行测试:

        HIGH=350 
        LOW=100 
        IFS=$(echo -en "\n\b") && for a in $(< yourfile.txt); do 
        VAR=$(grep -o "[0-9]*$" <<< "${a}")
        ((${VAR} < ${HIGH})) && ((${VAR} > ${LOW})) && sed "s/${a}/${var2}/"
        done 
        

        将 HIGH、LOW 值更改为您想要的任何范围。我认为这可能比awk 脚本更具可读性/可维护性,但awk 也可以处理这个问题。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-01-02
          • 2022-10-15
          • 2013-10-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-07-20
          相关资源
          最近更新 更多