如何在sed命令行中使用变量?

时间:2016-08-19 16:47:58

标签: bash variables sed

我有这个配置文件

# some other configuration settings
.....
wrapper.java.classpath.1=/opt/project/services/wrapper.jar
wrapper.java.classpath.2=/opt/project/RealTimeServer/RTEServer.jar
wrapper.java.classpath.3=/opt/project/mysql-connector-java-5.1.39-bin.jar
.....
# some other configuration settings

我希望它看起来像这样

# some other configuration settings
.....
wrapper.java.classpath.1=/opt/project/services/wrapper.jar
wrapper.java.classpath.2=/opt/project/RealTimeServer/RTEServer.jar
wrapper.java.classpath.3=/opt/project/mysql-connector-java-5.1.39-bin.jar
wrapper.java.classpath.4=/opt/project/RealTimeServer/some_other.jar
.....
# some other configuration settings

所以我写了这个bash shell

#!/bin/bash

CONF_FILE=$1
JAR_FILE=$2
DIR=$3

# Get the last wrapper.java.classpath.N=/some_path line
CLASSPATH=`awk '/classpath/ {aline=$0} END{print aline}' $CONF_FILE`
echo $CLASSPATH

# Get the left side of the equation
IFS='=' read -ra LS <<< "$CLASSPATH"

# Get the value of N
NUM=${LS##*\.}

# Increment by 1
NUM=$((NUM+1))
echo $NUM

NEW_LINE="wrapper.java.classpath.$NUM=$DIR/$JAR_FILE"
echo $NEW_LINE

# Append classpath line to conf file
sed "/$CLASSPATH/a \\${NEW_LINE}" $CONF_FILE

我这样称呼

./append_classpath.sh some_file.conf some_other.jar /opt/project/RealTimeServer

但是我得到了

sed: -e expression #1, char 28: unknown command: `o'

3 个答案:

答案 0 :(得分:0)

我刚看到你的shell脚本。 shell是一个可以调用工具的环境,它不是一个操作文本的工具。用于操作文本的标准通用UNIX工具是awk。您的整个shell脚本可以简化为:

$ dir="/opt/project/RealTimeServer"
$ jar_file="some_other.jar"
$ awk -v new="$dir/$jar_file" 'p~/classpath/ && !/classpath/{match(p,/([^=]+\.)([0-9]+)=/,a); print a[1] (++a[2]) "=" new} {print; p=$0}' file
# some other configuration settings
.....
wrapper.java.classpath.1=/opt/project/services/wrapper.jar
wrapper.java.classpath.2=/opt/project/RealTimeServer/RTEServer.jar
wrapper.java.classpath.3=/opt/project/mysql-connector-java-5.1.39-bin.jar
wrapper.java.classpath.4=/opt/project/RealTimeServer/some_other.jar
.....
# some other configuration settings

以上使用GNU awk为第3个arg匹配()。如果您必须在UNIX环境中操作文本,请阅读Arnold Robbins的“Effective Awk Programming,4th Edition”一书。

现在回到你的问题:

这是您正在尝试做的语法:

sed '/'"$some_string"'/a '"$some_line" "$some_file"

但是不要这样做,否则你会谴责自己变得神秘,不便携,不可维护,剥洋葱,逃避一切地狱(见Is it possible to escape regex metacharacters reliably with sed)!

sed用于单个行上的简单替换,即全部。其他任何事情,例如你在尝试什么,你应该使用awk:

awk -v regexp="$some_string" -v line="$some_line" '{print} $0~regexp{print line}' file

请注意,尽管您的shell变量名为“some_string”,但您在regexp上下文中使用它(您可以使用sed执行所有操作),因此我也在awk命令的regexp上下文中使用它并命名为awk变量“regexp” “为了清晰起见,而不是”字符串“(它只是一个变量名,但没有隐藏的含义)。

如果您确实希望将其视为字符串而非正则表达式,那么它应该是:

awk -v string="$some_string" -v line="$some_line" '{print} index($0,string){print line}' file

上面唯一的警告是,当awk变量从它们初始化时,shell变量中的反斜杠将被展开,因此\t将成为文字制表符。如果这是不合需要的,请告诉我们,我们可以提供一种替代语法来启动不扩展反斜杠的awk变量,请参阅http://cfajohnson.com/shell/cus-faq-2.html#Q24

答案 1 :(得分:0)

sed命令会对变量中的斜杠产生问题。 寻找一些独特的分隔符,例如#并尝试类似

CLASSPATH="wrapper.java.classpath.4=/opt/project/RealTimeServer/some_other.jar"
NEW_LINE="wrapper.java.classpath.5=your/data.rar"

echo "# some other configuration settings
.....
wrapper.java.classpath.1=/opt/project/services/wrapper.jar
wrapper.java.classpath.2=/opt/project/RealTimeServer/RTEServer.jar
wrapper.java.classpath.3=/opt/project/mysql-connector-java-5.1.39-bin.jar
wrapper.java.classpath.4=/opt/project/RealTimeServer/some_other.jar
.....
# some other configuration settings

Some more config lines
"  | sed "s#${CLASSPATH}#&\n${NEW_LINE}#"

答案 2 :(得分:0)

这是一个单程纯bash解决方案 - 如果配置文件不是很大,它应该没问题

pfx=wrapper.java.classpath.
while IFS= read -r line; do
  if [[ $line == $pfx*=* ]]; then
    lastclasspath=$line
  elif [[ -n $lastclasspath ]]; then
    newline=${lastclasspath#$pfx}
    num=${newline%%=*}
    newline="$pfx$((num+1))=$DIR/$JAR_FILE"
    echo "$newline"
    unset lastclasspath
  fi
  echo "$line"
done <$CONF_FILE