为什么这个 sed 命令什么都不做?

  • 本文关键字:sed 命令 bash shell sed
  • 更新时间 :
  • 英文 :


>我正在尝试cat一个文件以创建自己的副本,但同时替换一些值

我的命令是:

cat ${FILE} | sed "s|${key}|${value}|g" > ${TEMP_FILE}

但是,当我打开临时文件时,没有替换任何密钥 - 只是直接交换。我已经回显了键和值的值,它们是正确的 - 它们来自数组元素。

然而,如果我使用纯字符串而不是变量,它适用于一种类型的键 - 即:

cat ${FILE} | sed "s|example_key|${value}|g" > ${TEMP_FILE}

文件中的example_key实例被替换,这就是我想要的。

但是,当我尝试使用我的数组$key参数时,它什么也不做。不知道为什么:-(

命令用法:

declare -a props
...
....
for x in "${props[@]}"
do
key=`echo "${x}" | cut -d '=' -f 1`
value=`echo "${x}" | cut -d '=' -f 2`

# global replace on the $FILE
cat ${FILE} | sed "s|${key}|${value}|g" > ${TEMP_FILE}
#cat ${FILE} | sed "s|example_key|${value}|g" > ${TEMP_FILE}
done

数组元素以以下格式存储:$key=$value

key='echo "${x}" | cut -d '=' -f 1
value='echo "${x}" | cut -d '=' -f 2

如果要执行命令替换,请使用反引号,而不是单引号。

key=`echo "${x}" | cut -d '=' -f 1`
value=`echo "${x}" | cut -d '=' -f 2`

另请注意,当您循环遍历一系列key=value对时,您每次都会覆盖临时文件,仅使用应用于原始文件的一个替换。因此,在循环完成后,您所能希望的最好的结果是仅应用最后一个替换。


我还建议不要多次执行此操作 - 通过将多个表达式传递给 sed 来实现:

for x in "${props[@]}" ; do
subst="$subst -e 's=$x=g'"
done
sed $subst "${FILE}" > "${TEMP_FILE}"

我正在使用一个技巧,通过使用=作为 sed 替换表达式的分隔符,我们不必将键与值分开。 该命令只是变为:

sed -e 's=foo=1=g' -e 's=bar=2=g' "${FILE}" > "${TEMP_FILE}"

感谢@BillKarwin发现了问题的症结:循环的每次迭代都会清除以前迭代的替换,因为单个键值对替换的结果每次都会替换整个输出文件。

请尝试以下操作:

declare -a props
# ... 
cp "$FILE" "$TEMP_FILE"
for x in "${props[@]}"; do
IFS='=' read -r key value <<<"$x"
sed -i '' "s|${key}|${value}|g"  "${TEMP_FILE}"
done
  • 首先将输入文件复制到输出文件,然后在循环的每次迭代中就替换输出文件(使用sed-i选项)。
  • 我还简化了代码,使用read将每一行解析为键和值。
  • 另请注意,我一直对所有变量引用进行双重引用。
  • @anubhava提出了一个很好的一般观点:根据变量值,可能需要不同的正则表达式分隔符(在您的情况下:如果键或值包含"|",则不能使用"|"分隔正则表达式)。

更新:@BillKarwin提出了一个很好的观点:在循环中逐个执行替换是低效的。

这是一个完全避免循环的单行代码:

sed -f <(awk -F'=' '{ if ($0) print "s/" $1 "/" substr($0, 1+length($1)) "/g" }' 
"$FILE") "$FILE" > "$TEMP_FILE"
  • 使用awksed构建整套替换命令(每行一个)。
  • 然后通过进程替换将结果作为命令文件提供给sed-f
  • 正确处理嵌入=字符的情况。

相关内容

  • 没有找到相关文章