0

I am trying to assign the result of a sed command to a variable in bash, but I am unable to escape everything corrrectly (probably just due to my lack of knowledge in bash), I have tried:

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

but I am getting

bash_playground.sh: line 9: unexpected EOF while looking for matching `''

UPDATED SCRIPT

This is the script I am using updated with the code from the answer. Only the path and the comment have changed:

#!\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

executed with sh script_name.sh

sh --version yields:

GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin20) Copyright (C) 2007 Free Software Foundation, Inc.

On execution I get:

script_name.sh: line 6: unexpected EOF while looking for matching `"'
script_name.sh: line 10: syntax error: unexpected end of file
8
  • Can you add the data you are trying to match and the expected output?
    – sseLtaH
    Aug 27, 2021 at 9:59
  • the matching already works, when I execute the content of $() directly in the console I get a hexadecimal hash. The input is a file that contains a line that looks like this : pod 'XXX', :git => '[email protected]:ZZZ/AAA.git', :commit => '23401689216a1905bc137df'. The output in this case would be 23401689216a1905bc137df
    – Daniel
    Aug 27, 2021 at 10:11
  • You can try this sed -E 's/^pod.*>..(.*)./\1/' for the match.
    – sseLtaH
    Aug 27, 2021 at 10:18
  • @HatLess that does not seem to return the hash (it returns the whole file)
    – Daniel
    Aug 27, 2021 at 10:22
  • 1
    You can't use a single quote inside a single-quoted string. You don't need to escape double quotes inside a single-quoted string.
    – Kusalananda
    Aug 27, 2021 at 10:36

3 Answers 3

4

There are two issues in your script:

  1. The sh on macOS is a very old version of the bash shell, and it has a bug that stops you from using unbalanced quotes in here-documents in command substitutions:

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

    (I had to press Ctrl+D after the ) at the end there.)

    You can get by this by installing a newer bash shell from the Homebrew package manager (or equivalent), or by using the zsh shell on macOS.

  2. The sed on macOS does not have an -r option. To use extended regular expressions with sed on macOS, use -E (this is also supported by GNU sed nowadays). Your expression does not use extended regular expression features though, so just removing the option would be ok too. macOS sed also can't use - as the option-argument to -f to mean "read from standard input". Use /dev/stdin instead.

Suggestion:

#!/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

If all you want to do is to output the value, then don't use an intermediate variable:

#!/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
3

If the heredoc approach doesn't work for your system, then you can go fir an alternative of providing sed commands via shell variables:

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

Although there are many ways you could do this, but the simplest is to supply the sed commands on the stdin via a quoted heredoc so that there is no need to escape sed characters which are meaningful for the shell.

hash_in_podfile=$(sed -rnf - <<\! -- "${PODS_PODFILE_DIR_PATH}/Podfile"
s/^ *pod ['"]XXX["'],.*:commit *=> *["']([^'"]*)["'].*$/\1/p
!
)
9
  • I get: unexpected EOF while looking for matching `"'
    – Daniel
    Aug 27, 2021 at 10:33
  • In my test script I only have:
    – Daniel
    Aug 27, 2021 at 10:36
  • @Daniel You won't get that error if you use the command in the answer.
    – Kusalananda
    Aug 27, 2021 at 10:37
  • In my test script I only have: PODS_PODFILE_DIR_PATH='~/path/to/file' + yourcode + echo $hash_in_podfile (on different lines), and I execute it with sh testscript.sh. I have no idea what I could be doing wrong. Im on OSX, in case that could be breaking things...
    – Daniel
    Aug 27, 2021 at 10:38
  • The ~ will not expand to the path of your home directory if it's quoted. This should give you a "file not found" or "no such file or directory" error.
    – Kusalananda
    Aug 27, 2021 at 10:40
1
hash_in_podfile="$( sed -rn 's/^ *pod ['\''"]XXX["'\''],.*:commit *=> *["'\'']([^'\''"]*)["'\''].*$/\1/p' "${PODS_PODFILE_DIR_PATH}/Podfile" )"

The basic “trick” is in the way single-quotes are “escaped” within single-quotes: echo 'before'\''after' yields before'after. Given the way Bash expansion works, this will form a single token, as expected. An equivalent option would be echo 'before'"'"'after', but the former syntax is slightly shorter.

To check whether the expanded command looks right, just print it out:

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

BTW, it is good practice to use up-to-date software (e.g. version 5.1.8 in case of Bash) instead of badly outdated versions. In some cases a huge version discrepancy can make problems hard to reproduce and advice hard to follow.

3
  • 2
    Regarding your last paragraph: It depends. If you're writing for macOS, you may want to remain portable by writing your scripts in such a way that the default version of bash on the system is able to execute the code. Doing that ensures that the shell code will be valid on any current macOS system. Release 3.2.57 of bash is very old, but it's going to remain the default version of that shell on macOS for the foreseeable future.
    – Kusalananda
    Aug 27, 2021 at 15:56
  • Admittedly, I had no clue about this limitation of macOS and generally didn’t consider flawed software environments in that paragraph. I prefer environments with rolling updates where individual components (such as Bash) have individual versions (up-to-date rather than frozen) and are updated independently. So my assumption was that even if a system gets installed with old Bash, it will eventually update the package. The fact that an old version needs to be kept forever is quite surprising to me. Aug 27, 2021 at 16:14
  • In this particular case, it comes down to licensing issues.
    – Kusalananda
    Aug 27, 2021 at 16:18

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .