2

how can i get the string between two specific characters, only in bash [with out using grep or sed]

e.g

input=hostname~web:sit

I want to extract web from the above input

${hostname#*~} gives me output as web:sit, but i need only web in the output

From the other post i can see

% strips from end of $var, up to pattern. But not sure how to apply it.

Any help please

upog
  • 4,965
  • 8
  • 42
  • 81
  • 1
    Try `sed -E 's/.*~([^:]+):.*/\1/' <<< "$input"` – anubhava Mar 24 '21 at 19:27
  • `awk -F '[~:]' '{print $2}' <<< "$input"` – Jetchisel Mar 24 '21 at 19:40
  • @0stone0: That doesn't seem right dupe because that is `grep` specific question and here OP wants to do this in `bash` itself. – anubhava Mar 24 '21 at 20:10
  • There's a bash only solution just below your answer. Not using the extglob, however the question still remains the same? – 0stone0 Mar 24 '21 at 20:11
  • No questions cannot be same as other question is specifically asking **using grep** – anubhava Mar 24 '21 at 20:13
  • Does this answer your question? [How to use sed/grep to extract text between two words?](https://stackoverflow.com/questions/13242469/how-to-use-sed-grep-to-extract-text-between-two-words?noredirect=1&lq=1) – 0stone0 Mar 24 '21 at 20:13
  • Unfortunately that is also not correct dupe because that is asking how to do that in `sed/grep`. Please understand `bash` is different language and `grep/sed/awk` are different. – anubhava Mar 24 '21 at 20:16
  • Yea, I understand there's a difference between sed, grep and bash. Kinda contradict to give an sed answer on this bash question anyway. – 0stone0 Mar 24 '21 at 20:18
  • If I wanted to post just `sed` based answer I could have posted about an hour ago. That is the reason I just left that as comment only. I posted an answer only when I got a bash only solution working. – anubhava Mar 24 '21 at 20:21

3 Answers3

2

Do it in two steps:

input=hostname~web:sit

rightpart=${input#*~}   # remove prefix up to "~" (included)
output=${rightpart%:*}  # remove suffix from ":" (included)

echo $output
Pierre François
  • 5,850
  • 1
  • 17
  • 38
2

Using extglob in bash, you can do this in single step:

shopt -s extglob
input='hostname~web:sit'
echo "${input//@(*~|:*)/}"

web

Here @(*~|:*) matches a substring from start to ~ character OR a substring from : to end. Using // we replace all such instances with an empty string.


There is a sed solution as well:

sed -E 's/.*~([^:]+):.*/\1/' <<< "$input"

web
anubhava
  • 761,203
  • 64
  • 569
  • 643
  • Thanks for your answer, when i try the commands the echo is printing the input back instead of `web` -bash-4.2$ input='hostname~web:sit' -bash-4.2$ echo "${input//@(*~|:*)/}" hostname~web:sit – upog Mar 24 '21 at 20:03
  • Sorry I missed copying `shopt` line in answer. Please try updated answer now. – anubhava Mar 24 '21 at 20:05
1

Another option, using cut wich is available from the GNU Core Utilities:

  1. Get all behind ~
  2. Get all before :
input='hostname~web:sit'
echo "$input" | cut -d '~' -f2 | cut -d ':' -f1
# web

Try it online!

0stone0
  • 34,288
  • 4
  • 39
  • 64