【问题标题】:how to replace a variable in shell script string如何替换shell脚本字符串中的变量
【发布时间】:2012-11-02 15:55:26
【问题描述】:

我在让它工作时遇到问题......

我有一个使用占位符保存 SQL 的变量:

echo $SQL
SELECT PX_PROMOTION_ID, PRIORITY, STATUS, EXCLSVE, TYPE, PERORDLMT, PERSHOPPERLMT, TOTALLMT, RSV_INT, PX_GROUP_ID, CAMPAIGN_ID, STOREENT_ID, VERSION, REVISION, EFFECTIVE, TRANSFER, CDREQUIRED, EXPIRE, LASTUPDATEBY, TO_CHAR(LASTUPDATE, 'YYYYMMDD HH24MMSS') AS LASTUPDATE, TO_CHAR(STARTDATE, 'YYYYMMDD HH24MMSS') AS STARTDATE, TO_CHAR(ENDDATE, 'YYYYMMDD HH24MMSS') AS ENDDATE, TO_CHAR(RSV_TIME, 'YYYYMMDD HH24MMSS') AS RSV_TIME, RSV_REAL, TGTSALES, NAME, CODE, RSV_VCH, OPTCOUNTER FROM PX_PROMOTION WHERE LASTUPDATE BETWEEN (SELECT MAX(BATCHSTART) FROM XRPTEBATCHCONTROL) AND TIMESTAMP('$BATCH_END')

我有另一个变量保存该值:

echo $BATCH_END
2012-11-14 17:06:13

我想用值替换占位符。我不是特别擅长 Unix 脚本,但我试过这个:

echo $SQL | sed -e "s/'$BATCH_END/$BATCH_END/g"

但它仍然没有被替换......

有人可以帮忙吗?我想替换占位符,并保留分配给 $SQL 的最终字符串

我还需要知道如何将输出的值返回到变量中,例如我试过:

 SQL=`echo "$SQL" | echo "${SQL//\$BATCH_END/$BATCH_END}"`

【问题讨论】:

  • 回声太多。请改用SQL="${SQL//\$BATCH_END/$BATCH_END}"
  • Here 是这个问题的一个更一般的版本,涵盖了所有变量的替换,而无需事先知道变量将被命名。

标签: bash shell


【解决方案1】:

您的脚本中缺少单引号对的结尾。

更改自:

echo $SQL | sed -e "s/'$BATCH_END/$BATCH_END/g"

收件人:

echo $SQL | sed -e "s/\$BATCH_END/$BATCH_END/g"

更新 - 根据后续评论:

要将上述替换的结果保存回$SQL,请执行以下任一操作:

# Preferred way
SQL=$(echo $SQL | sed -e "s/\$BATCH_END/$BATCH_END/g")

# Old way
SQL=`echo $SQL | sed -e "s/\$BATCH_END/$BATCH_END/g"`

这称为command substitution。任何一种语法($(...) 与反引号包围)都可以,但首选的语法允许您进行嵌套。

首选-首选方式:Herestring

这可能比您关心的要高级一些,但是按照以下方式执行此操作将使您不必使用 echo 不必要的子进程:

SQL=$(sed -e "s/\$BATCH_END/$BATCH_END/g" <<< $SQL)

【讨论】:

  • 替换值仍然需要引号。
  • 好的,我知道了:SQL=echo $SQL | sed -e "s/\$BATCH_END/$BATCH_END/g",但是虽然 SED 现在似乎是,但返回的分配不起作用。如何将其分配回 SQL 变量?
  • @RichardG 查看我的更新答案,将替换的结果分配回 SQL 变量,我认为这就是您要寻找的。​​span>
【解决方案2】:

在我的终端中:

$ SQL="SELECT PX_PROMOTION_ID, PRIORITY, STATUS, EXCLSVE, TYPE, PERORDLMT, PERSHOPPERLMT, TOTALLMT, RSV_INT, PX_GROUP_ID, CAMPAIGN_ID, STOREENT_ID, VERSION, REVISION, EFFECTIVE, TRANSFER, CDREQUIRED, EXPIRE, LASTUPDATEBY, TO_CHAR(LASTUPDATE, 'YYYYMMDD HH24MMSS') AS LASTUPDATE, TO_CHAR(STARTDATE, 'YYYYMMDD HH24MMSS') AS STARTDATE, TO_CHAR(ENDDATE, 'YYYYMMDD HH24MMSS') AS ENDDATE, TO_CHAR(RSV_TIME, 'YYYYMMDD HH24MMSS') AS RSV_TIME, RSV_REAL, TGTSALES, NAME, CODE, RSV_VCH, OPTCOUNTER FROM PX_PROMOTION WHERE LASTUPDATE BETWEEN (SELECT MAX(BATCHSTART) FROM XRPTEBATCHCONTROL) AND TIMESTAMP('\$BATCH_END')"
$ # (observe: I escaped the $ sign to have the same variable as you)
$ echo "$SQL"
SELECT PX_PROMOTION_ID, PRIORITY, STATUS, EXCLSVE, TYPE, PERORDLMT, PERSHOPPERLMT, TOTALLMT, RSV_INT, PX_GROUP_ID, CAMPAIGN_ID, STOREENT_ID, VERSION, REVISION, EFFECTIVE, TRANSFER, CDREQUIRED, EXPIRE, LASTUPDATEBY, TO_CHAR(LASTUPDATE, 'YYYYMMDD HH24MMSS') AS LASTUPDATE, TO_CHAR(STARTDATE, 'YYYYMMDD HH24MMSS') AS STARTDATE, TO_CHAR(ENDDATE, 'YYYYMMDD HH24MMSS') AS ENDDATE, TO_CHAR(RSV_TIME, 'YYYYMMDD HH24MMSS') AS RSV_TIME, RSV_REAL, TGTSALES, NAME, CODE, RSV_VCH, OPTCOUNTER FROM PX_PROMOTION WHERE LASTUPDATE BETWEEN (SELECT MAX(BATCHSTART) FROM XRPTEBATCHCONTROL) AND TIMESTAMP('$BATCH_END')
$ BATCH_END="2012-11-14 17:06:13"
$ echo "$BATCH_END"
2012-11-14 17:06:13
$ # Now the replacement:
$ echo "${SQL//\$BATCH_END/$BATCH_END}"
SELECT PX_PROMOTION_ID, PRIORITY, STATUS, EXCLSVE, TYPE, PERORDLMT, PERSHOPPERLMT, TOTALLMT, RSV_INT, PX_GROUP_ID, CAMPAIGN_ID, STOREENT_ID, VERSION, REVISION, EFFECTIVE, TRANSFER, CDREQUIRED, EXPIRE, LASTUPDATEBY, TO_CHAR(LASTUPDATE, 'YYYYMMDD HH24MMSS') AS LASTUPDATE, TO_CHAR(STARTDATE, 'YYYYMMDD HH24MMSS') AS STARTDATE, TO_CHAR(ENDDATE, 'YYYYMMDD HH24MMSS') AS ENDDATE, TO_CHAR(RSV_TIME, 'YYYYMMDD HH24MMSS') AS RSV_TIME, RSV_REAL, TGTSALES, NAME, CODE, RSV_VCH, OPTCOUNTER FROM PX_PROMOTION WHERE LASTUPDATE BETWEEN (SELECT MAX(BATCHSTART) FROM XRPTEBATCHCONTROL) AND TIMESTAMP('2012-11-14 17:06:13')

完成!

【讨论】:

  • 好的,这是一种简洁的方法,而不是 SED,但是我如何将它分配回 SQL 变量,尝试:SQL=echo "${SQL//\$BATCH_END/$BATCH_END}"
  • 你应该可以这样使用:SQL=${SQL//\$BATCH_END/$BATCH_END}。在某些 shell 中,您可能需要在分配的 RHS 周围加上双引号,但在 bash 中则不需要(并且只有 bash,AFAIK 支持参数扩展上的 // 修饰符 - 尽管发现这一点并不让我感到惊讶zsh 也是)。
  • 很好地列出了所有使用过的命令!帮助了解发生了什么。
  • 如何在 ksh 中实现相同的功能。相同的脚本说替换错误
【解决方案3】:

您需要引用第一个 $,这样它就不会被扩展为 shell 变量。

echo "$SQL" | sed -e "s/'\$BATCH_END'/'$BATCH_END'/g"

…或者选择一个更简单的占位符,例如@BATCH_END@

要将结果分配回$SQL,您需要更多的外壳转义:

SQL=`echo "$SQL" | sed -e "s/'\\\$BATCH_END'/'$BATCH_END'/g"`

【讨论】:

  • 强烈推荐SQL=$(...) 而不是SQL=`...`
【解决方案4】:

一种方法是在单个参数中使用“差异引用”:

echo "$SQL" | sed -e 's/$BATCH_END/'"$BATCH_END/g"

-e选项的第一部分是单引号,所以shell不会扩展第一个$BATCH_END,它可以匹配SQL语句中的单词。第二部分用双引号括起来,因此 shell 扩展了第二个 $BATCH_END 并将其文本放入 SQL 中。

如果您需要担心$BATCH_END 周围的单引号,您将不得不使用其他技巧;反斜杠可能是最简单的(无论如何这是一个可行的选择):

echo "$SQL" | sed -e "s/'\$BATCH_END'/'$BATCH_END'/g"

反斜杠阻止shell扩展第一个$BATCH_END,但没有反斜杠意味着第二个被扩展。在双引号内,单引号失去其“无扩展”属性。

【讨论】:

    【解决方案5】:

    问题是您在 shell 中使用了双引号字符串。在双引号字符串中,$BATCH_END 等变量被解释为 shell 变量并被插值。 ' 字符在双引号字符串中没有特殊含义;它不会阻止变量被插值。所以你的$BATCH_END 字符串在两个地方都被替换了;您的 sed 调用相当于:

    sed -e "s/'2012-11-14 17:06:13/2012-11-14 17:06:13/"
    

    如您所见,这不是很有帮助(您还有一个流浪的')。您需要转义 $ 符号,以防止它被解释为 shell 变量:

    sed -e "s/\$BATCH_END/$BATCH_END/"
    

    【讨论】:

      【解决方案6】:

      redis.conf中“maxmemory”添加80%内存的情况:

      # GET TOTAL MEMORY
      totalmemory=$(awk '{ printf "%.2f", $2/1024 ; exit}' /proc/meminfo | awk -F"." '{print $1}');
      
      # CALCUL
      ramredis=$(echo $totalmemory/100*80 | bc);
      
      # APPLY
      sed -i 's/#maxmemory/maxmemory x mb/g' /etc/redis.conf;sed -i 's/ x /'\ $ramredis'/g' /etc/redis.conf;
      

      【讨论】:

        【解决方案7】:

        使用双引号

        sed -i "s/targetString/$newName/g" targetFile.toml
        

        【讨论】:

          猜你喜欢
          • 2014-11-24
          • 2023-03-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多