Given this stream:

[foo] 123 [bar]
[gar] dsa [har] 345
[uf] 88 [gc] 43 [br]

I want to process this with sed (or anything else) so the output would be:

foo bar
gar har
uf gc br

I tried cat myfile | sed -e 's/^.*\[//;s/\].*$//'

But it gives me only the last instance.

My real input is something like:

53f42d4 [the contacts are duplicated] Adding support in picking email verified users [https://trello.com/c/663]
3c454b0 [the contacts are duplicated] splitting contact by phone numbers and emails and changing contact model to contain only 1 email [https://trello.com/c/663]
0e63e5b [we should not let a user confirm his email if we have a user with this confirmed email already] better doc [https://trello.com/c/643]
02671b7 [we should not let a user confirm his email if we have a user with this confirmed email already] preventing updating email if already in used by other user [https://trello.com/c/643]

So I'd like to get for the first line:

the contacts are duplicated https://trello.com/c/663
up vote 3 down vote accepted

awk works well for this too: using [ or ] as the field separator, print every even-numbered field:

awk -F '[][]' '{for (i=2; i<=NF; i+=2) {printf "%s ", $i}; print ""}' file

With sed, I'd write

sed -E 's/(^|\])[^[]*($|\[)/ /g' file
  • The sed solution adds leading and trailing spaces (per line). – Isaac Oct 18 at 22:17

This will match anything inside the first (opening) square bracket to the first (closing) square bracket that follows, several times.

$ sed 's/[^[]*\[\([^]]*\)\][^[]*/\1 /g' file
foo bar
gar har
uf gc br

Description:

sed '                      # start a sed script
        s/                 # start a substitute command
        [^[]*              # match all leading characters (except [)
        \[                 # match an explicit [
        \([^]]*\)          # capture text inside brackets.
        \]                 # match the closing ]
        [^[]*              # match trailing text (if any).
        /\1 /              # replace everything matched by the captured text.
        g                  # repeat for all the line.
       ' file              # close script. Apply to file.

This add a trailing space per match. If that must be removed, add a removal at the end:

sed -e 's/[^[]*\[\([^]]*\)\][^[]*/\1 /g' -e 's/ $//' file

If you have GNU grep, this may help (one line per capture).

grep -Po '\[\K[^]]*(?=])'

And, if the above doesn't work, awk could also do it:

awk '{print gensub(/\[([^]]*)\][^[]*/,"\\1 ","g")}' file

An idiomatic way to do that is using look around assertions, see e.g. https://www.regular-expressions.info/lookaround.html, but these are not supported in sed, only in PCRE compliant regular expression processors.

Since Perl should be available on macOS by default, perhaps this is a viable alternative.

Using Perl, you could say

perl -pe 's/.+?(?<=\[)(.+?)(?=\]).+?/$1 /g'

(note that this adds a space at the end of the line)

For an explanation of the pattern, see https://regexr.com/41gi5.

  • Nice. An alternative: perl -nE 'say join " ", (/ (?<=\[) .*? (?=\]) /xg)' file – glenn jackman Oct 18 at 16:29

This seems to work:

$ sed -E 's/ [^[][a-zA-Z0-9][^]]/ /g;s/ +/ /g' input | tr -d '[]'
foo bar
gar har
uf gc br
  • thanks, but I get sed: input: No such file or directory – YardenST Oct 18 at 15:32
  • @YardenST "input" was a placeholder for an input file you would need to supply yours there or omit that and pipe in the source. – Chris Stratton Oct 18 at 15:37
  • Thanks got it :) but it does not seem to work with my input. My input is coming from git log commit1..commit2 --oneline. Ive updated the question with an example – YardenST Oct 18 at 15:42

Use:

sed -n '/\[/ { s-[^[]*--; s-\[\([^]]*\)\][^[]*- \1-g; s- --p }'

The algorithm is:

  • Ignore lines that do not contain brackets.
  • Remove text before first bracket.
  • Replace pairs of brackets and optional trailing text by spaces, leaving the text inside the brackets.
  • Remove the initial space, leaving only spaces in between.

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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