在 Mac 终端上的 sh -c 调用中转义单引号

escaping single quotes inside a sh -c call on Mac terminal

我正在尝试将一系列操作传递到 xargs 调用中,我可以使用它来使用 sed 命令交换第一个值和第二个值(如果有更好的方法,sed 是可选的)。

基本上我是在获取驼峰式大小写的方法签名,并在尝试保留驼峰式大小写的同时附加一个前缀。

所以应该...

originalMethodSignature

并将其替换为...

givenOriginalMethodSignature

因为我正在使用一系列管道来查找和修改文本,所以我希望将多个参数与 xargs 一起使用,但似乎涉及该问题的大多数问题都使用 sh -c,这将是很好,但是为了使 sed 命令在 Mac 终端上交互,我需要在 shell 调用的单引号内使用单引号。

像这样,双引号保留了 sed 命令中单引号的功能...

echo "somePrecondition SomePrecondition" | xargs -L1 sh -c 'find ~/Documents/BDD/Definitions/ -type f -name "Given.swift" -exec sed -i "''" "'"s/ [=14=]/ given/g"'" {} +'

假设有一个名为“~/Documents/BDD/Definitions/GivenSomePrecondition.swift”的文件,代码如下...

protocol GivenSomePrecondition { }

extension GivenSomePrecondition {
    func somePrecondition() {
        print("empty")
    }
}

第一个 awk 正在检查以 Given 关键字(例如 GivenSomePrecondition)开头的 swift 协议列表,然后在到达最终管道之前将其剥离为“somePrecondition SomePrecondition”。 我的意图是最终的 xargs 调用可以交互地用给定的 $1 替换 $0(覆盖文件)。

上下文中的原始命令...

awk '{ if ( ~ /^Given/) print [=12=];}' ~/Documents/Sell/SellUITests/BDDLite/Definitions/HasStepDefinitions.swift \
  | tr -d "\t" \
  | tr -d " " \
  | tr -d "," \
  | sort -u \
  | xargs -I string sh -c 'str=$(echo string); echo ${str#"Given"}' \
  | awk '{ print tolower(substr(,1,1)) substr(, 2)" " }' \
  | xargs -L1 sh -c '
      find ~/Documents/Sell/SellUITests/BDDLite/Definitions/ \
        -type f \
        -name "Given.swift" \
        -exec sed -i '' "'"s/ [=12=]/ given/g"'" {} +'

您不需要 xargssh -c,将它们取出可以减少所涉及的工作量。

echo "somePrecondition SomePrecondition" |
  while read -r source replace; do
    find ~/Documents/BDD/Definitions/ -type f -name "Given${replace}.swift" -print0 |
      while IFS= read -r -d '' filename; do
        sed -i '' -e "s/ ${source}/ given${replace}/g" "$filename"
      done
  done

但是,为了回答您的问题而不是回避它,您可以编写函数,使用您想要的任何类型的引号,并将它们导出到您的子 shell 中,或者在父进程中使用 export -f yourFunction,或者将 "$(declare -f yourFunction)" 放入 bash -c 之后传递的字符串中(假设 bash 是父进程中使用的相同 shell 定义 那些函数)。

#!/usr/bin/env bash

replaceOne() {
  local source replace
  source=; shift || return
  replace=; shift || return
  sed -i '' -e "s/ / given/g" "$@"
}

# substitute replaceOne into a new copy of bash, no matter what kind of quotes it has
bash -c "$(declare -f replaceOne)"'; replaceOne "$@"'