正确分配 sed 命令

正确分配 sed 命令

我试图将 sed 命令的结果分配给 bash 中的变量,但我无法正确转义所有内容(可能只是由于我缺乏 bash 知识),我尝试过:

hash_in_podfile=$( sed -rn 's/^ *pod [\'\"]XXX["\'],.*:commit *=> *["\']([^\'"]*)["\'].*$/\1/p' ${PODS_PODFILE_DIR_PATH}/Podfile )

但我越来越

bash_playground.sh:第 9 行:寻找匹配的“”时出现意外的 EOF

更新的脚本

这是我正在使用的脚本,已使用答案中的代码进行更新。仅路径和注释发生了变化:

#!\bin\sh
PODS_PODFILE_DIR_PATH='/Users/path/to/file'

# just a comment
hash_in_podfile=$(sed -rnf - <<\! -- "${PODS_PODFILE_DIR_PATH}/Podfile"
s/^ *pod ['"]XXX["'],.*:commit *=> *["']([^'"]*)["'].*$/\1/p
!
)
echo $hash_in_podfile

执行与sh script_name.sh

sh --version产量:

GNU bash,版本 3.2.57(1)-release (x86_64-apple-darwin20) 版权所有 (C) 2007 Free Software Foundation, Inc.

执行时我得到:

script_name.sh: line 6: unexpected EOF while looking for matching `"'
script_name.sh: line 10: syntax error: unexpected end of file

答案1

您的脚本中有两个问题:

  1. macOS 上的shellsh是一个非常旧的版本bash,它有一个错误,会阻止您在命令替换中的此处文档中使用不平衡引号:

    $ a=$( cat <<'END'
    > "
    > END
    > )
    > sh: unexpected EOF while looking for matching `"'
    

    (我必须在最后按Ctrl+D)

    您可以通过从 Homebrew 包管理器(或等效工具)安装较新的 shell 或在 macOS 上bash使用shell来解决此问题。zsh

  2. macOSsed上没有这个-r选项。要在sedmacOS 上使用扩展正则表达式,请使用-E(现在 GNU 也支持sed)。不过,您的表达式不使用扩展正则表达式功能,因此只需删除该选项也可以。 macOSsed也不能用作-选项参数来-f表示“从标准输入读取”。代替使用/dev/stdin

建议:

#!/bin/zsh

PODS_PODFILE_DIR_PATH='/Users/path/to/file'

# just a comment

hash_in_podfile=$(sed -n -f /dev/stdin -- $PODS_PODFILE_DIR_PATH/Podfile <<'END'
s/^ *pod ['"]XXX["'],.*:commit *=> *["']([^'"]*)["'].*$/\1/p
END
)

echo $hash_in_podfile

如果您只想输出值,则不要使用中间变量:

#!/bin/zsh

PODS_PODFILE_DIR_PATH='/Users/path/to/file'

# just a comment

sed -n -f /dev/stdin -- $PODS_PODFILE_DIR_PATH/Podfile <<'END'
s/^ *pod ['"]XXX["'],.*:commit *=> *["']([^'"]*)["'].*$/\1/p
END

答案2

如果该heredoc方法不适用于您的系统,那么您可以选择通过 shell 变量提供 sed 命令的替代方案:

hash_in_podfile=$(q=\"\'; sed -ne "s/^ *pod [$q]XXX[$q],.*:commit *=> *[$q]([^$q]*)[$q].*\$/\\1/p" -- "${PODS_PODFILE_DIR_PATH}/Podfile")

尽管有很多方法可以做到这一点,但最简单的方法是通过引用的heredoc在stdin上提供sed命令,这样就不需要转义对shell有意义的sed字符。

hash_in_podfile=$(sed -rnf - <<\! -- "${PODS_PODFILE_DIR_PATH}/Podfile"
s/^ *pod ['"]XXX["'],.*:commit *=> *["']([^'"]*)["'].*$/\1/p
!
)

答案3

hash_in_podfile="$( sed -rn 's/^ *pod ['\''"]XXX["'\''],.*:commit *=> *["'\'']([^'\''"]*)["'\''].*$/\1/p' "${PODS_PODFILE_DIR_PATH}/Podfile" )"

基本的“技巧”是在单引号内“转义”单引号的方式:echo 'before'\''after'yields before'after。考虑到 Bash 扩展的工作方式,这将形成一个单一的令牌,正如预期的那样。等效的选项是echo 'before'"'"'after',但前一个语法稍微短一些。

要检查扩展命令是否正确,只需将其打印出来:

echo sed -rn 's/^ *pod ['\''"]XXX["'\''],.*:commit *=> *["'\'']([^'\''"]*)["'\''].*$/\1/p' "${PODS_PODFILE_DIR_PATH}/Podfile"

顺便说一句,最好使用最新的软件(例如,Bash 的版本为 5.1.8),而不是严重过时的版本。在某些情况下,巨大的版本差异可能会导致问题难以重现并且建议难以遵循。

相关内容