繁体   English   中英

在 bash sed 命令中使用变量作为替换

[英]Use a variable as replacement in bash sed command

我在 Ubuntu 上使用sed命令来替换内容。

这个初始命令来自这里

sed -i '$ s/$/ /replacement/' "$DIR./result/doc.md"

但是,正如您所看到的,我在替换中使用了斜线。 斜线导致命令抛出:

sed: -e 表达式 #1, char 9: `s' 的未知选项

此外,我的替换存储在一个变量中。

因此,由于斜杠,以下内容不起作用:

sed -i "$ s/$/ $1/" "$DIR./result/doc.md"

正如此处和一式两份​​所述,我应该使用另一个分隔符。 如果我尝试@

   sed -i "$ s@$@ $1@" "$DIR./result/doc.md"

它给出了错误:

sed:-e 表达式 #1,字符 42:未终止的 `s' 命令

我的问题是:

如何在此命令中使用变量以及除/之外的其他分隔符?

不要在这里使用sed perlawk允许更强大的方法。

sed不允许变量从代码带外传递,因此它们总是需要转义。 使用没有这种限制的语言,您的代码始终有效,无论您的数据包含什么字符。

简短的回答:使用perl

以下内容摘自BashFAQ #21

inplace_replace() {
  local search=$1; shift; local replace=$1; shift
  in="$search" out="$replace" perl -pi -e 's/\Q$ENV{"in"}/$ENV{"out"}/g' "$@"
}
inplace_replace '@' "replacement" "$DIR/result/doc.md" 

更长的答案:使用awk

...或者,使用awk进行流式替换,并使用 shell 函数进行文件替换:

# usage as in: echo "in should instead be out" | gsub_literal "in" "out"
gsub_literal() {
  local search=$1 replace=$2
  awk -v s="${search//\\/\\\\}" -v r="${rep//\\/\\\\}" 'BEGIN {l=length(s)} {o="";while (i=index($0, s)) {o=o substr($0,1,i-1) r; $0=substr($0,i+l)} print o $0}'
}

# usage as in: inplace_replace "in" "out" /path/to/file1 /path/to/file2 ...
inplace_replace() {
  local search=$1 replace=$2 retval=0; shift; shift
  for file; do
    tempfile=$(mktemp "$file.XXXXXX") || { retval |= $?; continue; }
    if gsub_literal "$search" "$replace" <"$file" >"$tempfile"; then
      mv -- "$tempfile" "$file" || (( retval |= $? ))
    else
      rm -f -- "$tempfile" || (( retval |= $? ))
    fi
  done
}

特尔;博士:

尝试:

sed -i '$ s@$@ '"$1"'@' "$DIR./result/doc.md"

长版:

让我们从您的原始代码开始:

sed -i '$ s/$/ /replacement/' "$DIR./result/doc.md"

让我们将它与您引用的代码进行比较:

sed -i '$ s/$/abc/' file.txt

我们可以看到它们并不完全匹配。 我看到您正确地进行了此替换:

file.txt --> "$DIR./result/doc.md"

看起来不错(尽管我对 $DIR 之后的 . 有疑问)。 但是,其他替换看起来不太好:

abc -->  /replacement

您实际上引入了另一个分隔符 /。 但是,如果我们用“@”替换分隔符,我们会得到:

sed -i '$ s@$@ /replacement@' "$DIR./result/doc.md"

我认为上述内容在 sed/bash 中完全有效。 $@不会被 shell 替换,因为它是单引号的。 $DIR变量被 shell 插入,因为它是双引号的。

看看你的尝试之一:

sed -i "$ s@$@ $1@" "$DIR./result/doc.md"

由于双引号中 $@ 的 shell 插值,您将遇到问题。 让我们通过用单引号替换(但保留 $1 不加引号)来更正:

sed -i '$ s@$@ '"$1"'@' "$DIR./result/doc.md"

注意'"$1"'。 我不得不用 '' 包围 $1 以基本上取消周围的单引号。 但是后来我用双引号将 $1 括起来,这样我们就可以保护字符串免受空格的影响。

使用shell 参数扩展向变量中的斜杠添加转义:

$ cat file
foo
bar
baz

$ set -- ' /repl'

$ sed "s/$/$1/" file
sed: 1: "s/$/ /repl/": bad flag in substitute command: 'r'

$ sed "s/$/${1//\//\\\/}/" file
foo /repl
bar /repl
baz /repl

这是倾斜牙签的怪物,但它有助于改变这一点:

sed "s/$/ /repl/"

进入

sed "s/$/ \/repl/"

相同的技术可用于您选择作为 sed s///分隔符的任何内容。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM