Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/variables/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Bash 如何在sed命令行中使用变量?_Bash_Variables_Sed - Fatal编程技术网

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

Bash 如何在sed命令行中使用变量?,bash,variables,sed,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
.....
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
所以我写了这个bashshell

#!/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
但我明白了

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

我刚看到你的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作为第三个要匹配的参数()。如果您需要在UNIX环境中操作文本,请阅读Arnold Robbins的《高效Awk编程》第四版


现在回到你的问题:

这是您尝试执行的语法:

sed '/'"$some_string"'/a '"$some_line" "$some_file"
但不要这样做,否则你会让自己陷入神秘、不可携带、无法维护、剥洋葱皮、逃离地狱的境地(见)

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”,而不是“string”(虽然它只是一个变量名,没有隐藏的含义)

如果您确实希望将其视为字符串而不是regexp,那么:

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

上面唯一需要注意的是,当awk变量从外壳变量初始化时,外壳变量中的反斜杠将被展开,因此,例如,
\t
,将成为文本制表符。如果不需要,请告知我们,我们可以提供一种替代语法来初始化不展开反斜杠的awk变量,请参阅。

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}#"

这是一个一次性的纯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
pfx=wrapper.java.classpath。
而IFS=读取-r行;做
如果[[$line==$pfx*=*]];然后
lastclasspath=$line
elif[-n$lastclasspath]];然后
换行符=${lastclasspath#$pfx}
num=${newline%%=*}
换行符=“$pfx$((num+1))=$DIR/$JAR\u文件”
回显“$newline”
取消设置lastclasspath
fi
回音“$line”

完成了这里的变量是什么?给我们所有的信息。测试文件、变量以及您正在使用的操作系统和shell。只是一个简单的说明:试试“${some_string}”。$似乎只看到变量名的第一个字母。${some_line}也一样。@steffen:胡说。Karoly是正确的:-)@ChrisF-始终引用shell变量-
“$some\u file”
,而不是
$some\u file
!如果你不知道为什么那么谷歌它统计!另外,不要为非导出变量使用所有大写变量名,以避免与现有变量冲突。谢谢,但我尝试了此操作,但它没有附加行。注意,我在包装行之前和之后都有行。我将编辑我的帖子来反映这一点。你也错过了匹配的单引号,对吗?sed“/”“$some_string””/a“$some_line”“$some_file”。我也用过,但没有用,在我修正语法之后,事件。对,如果你的真实输入看起来不像你的样本输入,那么所有的赌注都是无效的。我可能错过了sed命令中的一句话,这无关紧要,因为它无论如何都不应该被使用。实际上,它只是引用了太多的一个引号。我调整了awk命令来处理您的新输入。如果它不适合您,请确保您使用的是GNU awk 4.0或更新版本。如果没有,就去拿吧。如果这是绝对不可能的,那么使用sub()和substr()的组合,而不是数组a[]。说清楚一点——我展示了sed语法来说明你要做的事情,我并不是想暗示它实际上会起作用(参见我所说的洋葱剥皮等)。谢谢,但不幸的是,新的awk命令没有附加我想要的行。我已经在CentOS 7.2上安装了gawk v4.0.2,它将遇到除斜杠以外的更多字符的问题,例如任何BRE regexp元字符、后跟数字的反斜杠或
&
。请参阅如何使用sed稳健地执行此操作。
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