42

I'm running this command in a bash shell on Ubuntu 12.04.1 LTS. I'm attempting to remove both the [ and ] characters in one fell swoop, i.e. without having to pipe to sed a second time.

I know square brackets have special meaning in a regex so I'm escaping them by prepending with a backslash. The result I was expecting is just the string 123 but the square brackets remain and I'd love to know why!

~$ echo '[123]' | sed 's/[\[\]]//'
[123]
3
  • What I'm trying to ultimately achieve is to assign whatever's between the square brackets to a bash variable for use elsewhere in my bash script, so if there's a better way to achieve that (by using awk, maybe?), please let me know.
    – Xhantar
    Jan 11, 2013 at 10:40
  • 2
    Just adding as a comment: You can use bash's PE feature as in: str='[123]'; str1=${str/\[/}; str2=${str1/\]}; echo $str2 Jan 11, 2013 at 11:08
  • 1
    @val0x00ff - Pure bash substitution.. thanks! :) Learned something new.
    – Xhantar
    Jan 11, 2013 at 12:13

5 Answers 5

57

This is easy, if you follow the manual carefully: all members inside a character class lose special meaning (with a few exceptions). And ] loses its special meaning if it is placed first in the list. Try:

$ echo '[123]' | sed 's/[][]//g'
123
$

This says:

  1. inside the outer [ brackets ], replace any of the included characters, namely:
    • ] and
    • [
  2. replace any of them by the empty string — hence the empty replacement string //,
  3. replace them everywhere (globally) — hence the final g.

Again, ] must be first in the class whenever it is included.

3
  • Live example: github.com/PHPExpertsInc/DockerUpgrade/blob/master/…
    – hopeseekr
    Sep 19, 2020 at 17:33
  • Is this behavior a characteristic of regex in general, or just sed? Apr 20, 2021 at 21:55
  • 2
    @user1079505, unfortunately there is no such thing stricty as "regex in general". Regex syntax has subtle variations in different environments (linux emacs, linux/unix utilities, shell, python, mongo, etc...). However, where character classes are allowed in regex, this is the typical behavior.
    – Saparagus
    Apr 21, 2021 at 9:37
13

I'm not sure why that doesn't work but this does:

echo '[123]' | sed 's/\(\[\|\]\)//g'

or this:

echo '[123]' | sed -r 's/(\[|\])//g'

You can also try a different approach and match the string inside the brackets (assuming the string can be matched easily and is not defined by the brackets):

echo '[123]' | egrep -o "[0-9]+"

I'm having the same troubles with your original regex using grep so I suspect this is not just a sed thing.

Weirdly, these produce different results but one of them matches what you want:

echo '[123]' | egrep -o '[^][]+'
123

echo '[123]' | egrep -o '[^[]]+'
3]

Applying this to your original sed (and adding the /g modifier so it removes both brackets):

echo '[123]' | sed 's/[][]//g'
123
4
  • Your 3rd approach (egrep -o...) looks like the cleanest solution to my problem. I'll only ever have integers in between the square brackets (and sorry, I should have mentioned that in my question) so I shouldn't run into any oddities I think. Thanks!
    – Xhantar
    Jan 11, 2013 at 12:20
  • 6
    You can also use tr: echo '[123]' | tr -d '[]' - avoids regexp confusions about escaping. Jan 11, 2013 at 12:53
  • @James O'Gorman - Interesting. For some reason I thought that tr can only translate one character max at a time, but I was wrong. Thanks!
    – Xhantar
    Jan 11, 2013 at 13:41
  • A simple solution must mean a simple problem. Thanks @JamesO'Gorman.
    – D.Fitz
    Dec 24, 2023 at 1:21
3

To remove everything before and after the brackets :

$ echo '[123]' | sed 's/.*\[//;s/\].*//;'
123

If your data is like this always meaning starting and ending with square brackets:

$ echo '[123]' | sed 's/.//;s/.$//;'
123
2
  • The data I'm working with will always start and end with a square bracket yes. I'd still like to know why my solution wasn't working though. Any ideas? And is there a way to do this without specifying 2x regex's?
    – Xhantar
    Jan 11, 2013 at 10:49
  • 1
    @Guru this solution worked from me, and as for Xhantar ,This is a really late reply, but what I can see from your code and the Bash Beginners guide at tldp.org , you were trying to do multiple search and replace, one for '[' and the other for ']' which wont work, to space out two different search and replace use the ";" or the -e options. 's/<search>/<replace>/g ; s/<search>/<replace>/g' OR sed -e 's/<search>/<replace>/g' -e 's/<search>/<replace>/g'
    – ArunMKumar
    Sep 1, 2016 at 22:11
1

You can escape the opening bracket using \[. For the closing bracket, use []].

0

If you have a more complex string like 'abcdef[123]ghijk' you can also use internal bash command 'cut' to extract text only between square brackets:

$ echo 'abcdef[123]ghijk' | cut -d '[' -f 2 | cut -d ']' -f 1
123

You must log in to answer this question.

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