Hyph
Hyph

Reputation:

How can I capture the text between specific delimiters into a shell variable?

I have little problem with specifying my variable. I have a file with normal text and somewhere in it there are brackets [ ] (only 1 pair of brackets in whole file), and some text between them. I need to capture the text within these brackets in a shell (bash) variable. How can I do that, please?

Upvotes: 6

Views: 12946

Answers (10)

mica
mica

Reputation:

Using Bash builtin regex matching seems like yet another way of doing it:

var='foo[bar] pinch'
[[ "$var" =~ [^\]\[]*\[([^\[]*)\].* ]]   # Bash 3.0
var="${BASH_REMATCH[1]}"
echo "$var"

Upvotes: 2

cb0
cb0

Reputation: 8613

2 simple steps to extract the text.

  1. split var at [ and get the right part
  2. split var at ] and get the left part
cb0$ var='foo[bar] pinch'
cb0$ var=${var#*[}
cb0$ var=${var%]*} && echo $var
bar

Upvotes: 0

strager
strager

Reputation: 90022

Bash/sed:

VARIABLE=$(tr -d '\n' filename | sed -n -e '/\[[^]]/s/^[^[]*\[\([^]]*\)].*$/\1/p')

If that is unreadable, here's a bit of an explanation:

VARIABLE=`subexpression`      Assigns the variable VARIABLE to the output of the subexpression.

tr -d '\n' filename  Reads filename, deletes newline characters, and prints the result to sed's input

sed -n -e 'command'  Executes the sed command without printing any lines

/\[[^]]/             Execute the command only on lines which contain [some text]

s/                   Substitute
^[^[]*               Match any non-[ text
\[                   Match [
\([^]]*\)            Match any non-] text into group 1
]                    Match ]
.*$                  Match any text
/\1/                 Replaces the line with group 1
p                    Prints the line

Upvotes: 9

mica
mica

Reputation:

Backslashes (BSL) got munched up ... :

var='foo[bar] pinch' 
[[ "$var" =~ [^\]\[]*\[([^\[]*)\].* ]]   # Bash 3.0 
# Just in case ...: 
[[ "$var" =~ [^BSL]BSL[]*BSL[([^BSL[]*)BSL].* ]]   # Bash 3.0 
var="${BASH_REMATCH[1]}" 
echo "$var" 

Upvotes: 0

lhunath
lhunath

Reputation: 125406

May I point out that while most of the suggested solutions might work, there is absolutely no reason why you should fork another shell, and spawn several processes to do such a simple task.

The shell provides you with all the tools you need:

$ var='foo[bar] pinch'
$ var=${var#*[}; var=${var%%]*}
$ echo "$var"
bar

Upvotes: 6

Zsolt Botykai
Zsolt Botykai

Reputation: 51613

Sed is not necessary:

var=`egrep -o '\[.*\]' FILENAME | tr -d ][`

But it's only works with single line matches.

Upvotes: 3

Jonathan Leffler
Jonathan Leffler

Reputation: 753900

What about:

shell_variable=$(sed -ne '/\[/,/\]/{s/^.*\[//;s/\].*//;p;}' $file)

Worked for me on Solaris 10 under Korn shell; should work with Bash too. Replace '$(...)' with back-ticks in Bourne shell.

Edit: worked when given [ on one line and ] on another. For the single line case as well, use:

shell_variable=$(sed -n -e '/\[[^]]*$/,/\]/{s/^.*\[//;s/\].*//;p;}' \
                        -e '/\[.*\]/s/^.*\[\([^]]*\)\].*$/\1/p' $file)

The first '-e' deals with the multi-line spread; the second '-e' deals with the single-line case. The first '-e' says:

  • From the line containing an open bracket [ not followed by a close bracket ] on the same line
  • Until the line containing close bracket ],
  • substitute anything up to and including the open bracket with an empty string,
  • substitute anything from the close bracket onwards with an empty string, and
  • print the result

The second '-e' says:

  • For any line containing both open bracket and close bracket
  • Substitute the pattern consisting of 'characters up to and including open bracket', 'characters up to but excluding close bracket' (and remember this), 'stuff from close bracket onwards' with the remembered characters in the middle, and
  • print the result

For the multi-line case:

$ file=xxx
$ cat xxx
sdsajdlajsdl
asdajsdkjsaldjsal
sdasdsad [aaaa
bbbbbbb
cccc] asdjsalkdjsaldjlsaj
asdjsalkdjlksjdlaj
asdasjdlkjsaldja
$ shell_variable=$(sed -n -e '/\[[^]]*$/,/\]/{s/^.*\[//;s/\].*//;p;}' \
                          -e '/\[.*\]/s/^.*\[\([^]]*\)\].*$/\1/p' $file)
$ echo $shell_variable
aaaa bbbbbbb cccc
$

And for the single-line case:

$ cat xxx
sdsajdlajsdl
asdajsdkjsaldjsal
sdasdsad [aaaa bbbbbbb cccc] asdjsalkdjsaldjlsaj
asdjsalkdjlksjdlaj
asdasjdlkjsaldja
$
$ shell_variable=$(sed -n -e '/\[[^]]*$/,/\]/{s/^.*\[//;s/\].*//;p;}' \
                          -e '/\[.*\]/s/^.*\[\([^]]*\)\].*$/\1/p' $file)
$ echo $shell_variable
aaaa bbbbbbb cccc
$

Somewhere about here, it becomes simpler to do the whole job in Perl, slurping the file and editing the result string in two multi-line substitute operations.

Upvotes: 1

Hyph
Hyph

Reputation:

Thanks to everyone, i used Strager's version and works perfectly, thanks alot once again...

var=`grep -e '\[.*\]' test.txt | sed -e 's/.*\[\(.*\)\].*/\1/' infile.txt`

Upvotes: 0

John Ellinwood
John Ellinwood

Reputation: 14531

var=`grep -e '\[.*\]' test.txt | sed -e 's/.*\[\(.*\)\].*/\1/' infile.txt`

Upvotes: 0

jfs
jfs

Reputation: 414255

Assuming you are asking about bash variable:

$ export YOUR_VAR=$(perl -ne'print $1 if /\[(.*?)\]/' your_file.txt)

The above works if brackets are on the same line.

Upvotes: 1

Related Questions