如何替换shell脚本字符串中的变量

时间:2012-11-14 06:22:33

标签: bash shell

我在解决这个问题时遇到了问题...

我有一个带占位符的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}"`

6 个答案:

答案 0 :(得分:40)

您错过了脚本中单引号对的结尾。

更改自:

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)

答案 1 :(得分: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')

完成!

答案 2 :(得分:1)

您需要引用第一个$,以便它不会作为shell变量展开。

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

...或者选择一个更容易的占位符,例如@BATCH_END@

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

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

答案 3 :(得分:0)

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

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,但没有反斜杠意味着第二个会扩展。在双引号内,单引号失去了“无扩展”属性。

答案 4 :(得分:0)

问题是你在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/"

答案 5 :(得分:0)

在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;