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

Time:11-03

I'm trying to pipe a series of manipulations into an xargs call that I can use to swap the first value with the second using the sed command (sed is optional if there's a better way).

Basically I'm grabbing method signature in camel case and appending a prefix while trying to retain camel case.

So it should take...

originalMethodSignature

and replace it with...

givenOriginalMethodSignature

Because I'm using a series of pipes to find and modify the text, I was hoping to use multiple params with xargs, but it seems that most of the questions involving that use sh -c which would be fine but in order for the sed command to be interactive on a Mac terminal I need to use single quotes inside the shell calls' single quotes.

Something like this, where the double quotes preserve the functionality of the single quotes in the sed command...

echo "somePrecondition SomePrecondition" | xargs -L1 sh -c 'find ~/Documents/BDD/Definitions/ -type f -name "Given$1.swift" -exec sed -i "''" "'"s/ $0/ given$1/g"'" {} '

assuming there's a file called "~/Documents/BDD/Definitions/GivenSomePrecondition.swift" with below code...

protocol GivenSomePrecondition { }

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

The first awk is going through a list of swift protocols that start with the Given keyword (e.g. GivenSomePrecondition), then they strip it down to "somePrecondition SomePrecondition" before hitting the final pipe. My intent is that the final xargs call can replace $0 with given$1 interactively (overwriting the file).

The original command in context...

awk '{ if ($1 ~ /^Given/) print $0;}' ~/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,1)) substr($1, 2)" "$1 }' \
  | xargs -L1 sh -c '
      find ~/Documents/Sell/SellUITests/BDDLite/Definitions/ \
        -type f \
        -name "Given$1.swift" \
        -exec sed -i '' "'"s/ $0/ given$1/g"'" {}  '

CodePudding user response:

You don't need xargs or sh -c, and taking them out reduces the amount of work involved.

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

However, to answer your questions as opposed to sidestepping it, you can write functions that use any kind of quotes you want, and export them into your subshell, either with export -f yourFunction in a parent process or by putting "$(declare -f yourFunction)" inside the string passed after bash -c (assuming that bash is the same shell used in the parent process defining those functions).

#!/usr/bin/env bash

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

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