0

Hi I have one script that was running inside makefiles for project deployments. I use sed inside it to capture environment and project name from input string and in ubuntu works great.

This simple command

 echo deploy-api-production | sed -E 's/deploy-\w+-(\w+)/\1/'

gives expected result production in ubuntu

ubuntu execution

$  echo deploy-api-production | sed -E 's/deploy-\w+-(\w+)/\1/'
production

but in mac gives the entire full string deploy-api-production

mac execution:

$  echo deploy-api-production | sed -E 's/deploy-\w+-(\w+)/\1/'
deploy-api-production

Is there some kind of unified sed so I get same result in mac as well?

I want output to be only production in mac execution as well

Case 2 - more generic, including prefix as well

Want to parse this properly

echo a-deploy-api-production | someprocessing
production

So is similar to above case, but does has one extra prefix word a- before the word deploy

I tried something similar to current given solution but did not work

echo a-deploy-api-production | awk -F'-' '$1=="a-deploy"{print $3}'

result of above is empty, want to modify to get result production

3
  • 2
    Neither \w nor + are POSIX sed.
    – Philippos
    Apr 22 at 12:05
  • Hi the command I provided works fine on ubuntu. Can you please tell me what to use instead to get it work cross platform ? Apr 22 at 12:42
  • The portable form of \w is [[:alnum:]]; the portable form of + is {1,} (one or more occurences). So your litetal command is sed -E 's/deploy-[[:alnum:]]{1,}-([[:alnum:]]{1,})/\1/'. But in the end, it seems you are looking for sed '/deploy-/s/.*-//'
    – Philippos
    Apr 22 at 14:28

3 Answers 3

1

You can use awk:

echo deploy-api-production | awk -F'-' '$1=="deploy"{print $3}'

This splits the text into parts separated by -. It requires the first field to match the word deploy and then prints the third.

In your updated question you include a new variation. You cannot use the same awk code to directly compare a-deploy because that's two fields (remember, they are split by the dash), and $1 is only the first field (i.e. a instead of deploy in this new instance).

Without knowing all your use-cases I would suggest you may be happier to search for deploy anywhere in the string, and if it's found then print the last field. (This will also work for your original case.)

echo deploy-api-production | awk -F'-' '/deploy/ {print $NF}'
production

echo a-deploy-api-production | awk -F'-' '/deploy/ {print $NF}'
production
3
  • I tested on mac and ubuntu and works totally fine. Thank you for the knowledge here, marked as answer. For my learning, what if i add onoe extra word before deploy, this won't work for example echo a-deploy-api-production | awk -F'-' '$1=="a-deploy"{print $3}' I tried specifying also print $4 as I added one extra word a- before deploy still did not work Apr 22 at 12:52
  • Thanks updated question and added case 2 Apr 22 at 14:12
  • @KristiJorgji there you go
    – roaima
    Apr 22 at 14:41
0

With POSIX-ly sed, you can attain the required results for both scenarios, as shown:

w='[[:alpha:]][_[:alnum:]]*'
echo 'deploy-api-productionN' | 
sed -n -e "/^\($w-\)\{0,1\}deploy-/s/^$w\(-\($w\)\)\{1,\}\$/\2/p"

Observations:

  • since sed has no symbol for a word, we will build a regex for that and store them in shell variable $w
  • \{0,1\} is BRE for ?
  • \{1,\} is BRE for +
  • \(...\) is BRE for (...)
0

You get different results on the two systems because the GNU system uses a regular expression library that was extended to include some symbols from the type of regular expressions called PCRE (Perl Compatible Regular Expressions). These symbols, like \s and \w, are not standard and not supported with sed on all systems (typically not outside of GNU systems).

You seem to want to output the last part of a line after the last - (dash) if it starts with the substring deploy or something-deploy.

You can do that with standard sed using

sed '/^deploy/ s/.*-//'

or with

sed '/^something-deploy/ s/.*-//'

These sed expressions trigger the substitution s/.*-// if the preceding regular expression matches the current input line. Thi substitution removes everything up to and including the last dash on the line.

You can combine the triggering expression with the substitution in this case, if you want:

sed 's/^deploy.*-//'
sed 's/^something-deploy.*-//'

If your data is not static strings outputted by echo (as in the question) but some value in a variable, then it would be more efficient to let the shell do this rather than calling an external program:

string=deploy-api-production

if [[ $string == deploy-* ]]; then
    printf '%s\n' "${string##*-}"
fi

You will use a variable assignment rather than printf if you want to hold on to the modified value, as in new=${string##*-}.

The ${variable##pattern} expansion will remove the longest prefix string from $variable that matches the shell pattern pattern.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.