sed -i,引号为第一个arg

时间:2014-10-31 16:58:01

标签: bash shell sed

使用sed修复git pre-commit钩子中的空格,我遇到了问题: sed -i '' [the regex] [the file]

类似comments by others提到了这种不一致性,并且取出引号可以解决问题。这让我感到困惑,因为我认为sed -i应该在文件后面紧跟一个文件名作为参数。它可能是壳不一致;我链接的要点是.sh脚本,我使用bash / centos。

sed -i ''用法背后的魔力/问题是什么?如何解析''纠正问题?

2 个答案:

答案 0 :(得分:1)

正如@avinashraj在他们的评论中提到的BSD sed 需要 -i的参数,而GNU sed使该参数成为可选的(并且不允许在CentOS 5上进行快速测试的空间。

由于使用GNU sed的{​​{1}}行为将失败,因为它会假定sed -i '' 'script' file没有参数,请使用-i作为要运行的脚本,并使用{ {1}}作为第一个操作的文件。

使用''将解决'script'的脚本文件名问题,但会将sed -i '' -e 'script' file解释为文件名。

使用GNU sed解决 问题。

我不知道这对''是否合法。我希望sed -i'' -e 'script' file没问题。

问题是它是否接受了对BSD sed标志的后缀。

编辑:正如@CharlesDuffy准确地指出-e 'script'不可能接受-i或它也会接受BSD sed,因为它无法区分其参数处理中的那些(空字符串已经在那一点上消失了。)

这意味着,除非我错过了某些内容或-i''能够正确接受-i,否则我无法通过便携式方式进行此操作。

答案 1 :(得分:0)

下面的函数定义了一个sed_inplace命令,它试图在任何平台上做正确的事情。 (请注意,它需要bash作为shell)。

sed_inplace() {
  local -a args=( "$@" )
  local sed_version
  if sed_version=$(sed --version 2>&1) && [[ $sed_version = *'(GNU sed)'* ]]; then
    # the GNU version
    sed -i "$@"
  elif [[ $sed_version = *"[-i "* ]]; then
    # assuming this to be the BSD version with -i
    sed -i '' "$@"
  else
    # the generic version
    local file=${args[${#args[@]} - 1]}
    local tempfile=$(mktemp "${file}.XXXXXX")
    if sed "$@" <"$file" >"$tempfile"; then
      mv "$tempfile" "$file"
    else
      local rc=$?
      rm -f -- "$tempfile"
      return $rc
    fi
  fi
}

当然,如果您没有尝试使用sed -i,而是使用ex,则可以避免这种混乱。