5678 []
testing,\ group []
[testing []
ip\ 5.6.7.8 []
launch-wizard-1 0.0.0.0/0
456dlkjfa []
1.2.3.4 []
test 1.2.3.4/32 4.3.2.0/23 4.3.2.0/23
default 4.3.2.0/23 4.3.2.0/23
launch-wizard-2 0.0.0.0/0
launch-wizard-3 0.0.0.0/0
2.3.4.5/32 []

I would like to get the first column of the above but the catch is that, I need to treat \ (backslash space) as a part of the column, so awk '{print $1}' should give me

5678
testing,\ group
[testing
ip\ 5.6.7.8
launch-wizard-1
456dlkjfa
1.2.3.4
test
default
launch-wizard-2
launch-wizard-3
2.3.4.5/32
  • Is \ being treated as an escape character always or is only \ special? For instance, is a\\ b one field or two? – Gregory Nisbet Sep 25 at 23:49
  • @GregoryNisbet I've put in \ is for escape character, not the real data – GypsyCosmonaut Sep 26 at 0:13
  • 1
    If your data happened to contain a real backslash, how would it be represented? – Gregory Nisbet Sep 26 at 0:16
  • @GregoryNisbet Good question. Because I replaced only [[:space:]] with \[[:space:]], the original data has \ untouched in their place. After getting the original data in the first column delimited by only spaces and not \[[:space:]], I'd be replacing \[[:space:]] with [[:space:]] and I'd be left with original data back again which has \. – GypsyCosmonaut Sep 26 at 0:31
up vote 9 down vote accepted

with gnu awk (gawk) you can use some zero-length assertions like \< or \>:

$ echo 'a\ b c' | gawk 'BEGIN{FS="\\> +"} {print $1}'
a\ b

but unfortunately not the full-blown ones from perl or pcre (eg. (?<!\\), (?<=\w), etc):

$ echo 'a\ b, c' | perl -nle '@a=split /(?<!\\)\s+/, $_; print $a[0]'
a\ b,

You could substitute \space with something else and back again afterwards.

sed 's/\\ /\\x20/g' data_file | awk '{ print $1; }' | sed 's/\\x20/\\ /g'
  • Only with sed : sed 's/\\ /\\x20/g;s/ .*//;s/\\x20/\\ /g' data_file – ctac_ Sep 25 at 16:26
  • Or, awk, using the default SUBSEP variable value of \034: awk '{gsub(/\\ /,SUBSEP,$0); val=$1; gsub(SUBSEP,"\\ ",val); print val}' file – glenn jackman Sep 25 at 18:29

With GNU grep or compatible:

grep -Po '^(\\.|\S)*'

Or with ERE:

grep -Eo '^(\\.|[^\[:space:]])*'

That treats \ as a quoting operator, for whitespace as a delimiter, but also for itself. That is, on foo\\ bar input, it returns foo\\.

With just sed:

sed -r 's/^((([^\]*\\ ){1,})?[^ ]*).*/\1/' infile

Or shorter:

sed -r 's/^(([^\]*\\ )*[^ ]*).*/\1/' infile

This (([^\]*\\ ){1,})?[^ ]* matches:

  • [^\]*\\: anything that it's not a back-slash which ends with back-slash followed by a space (note that \ inside character class is not required to be escaped, but outside does).
  • ([^\]*\\ ){1,}: matching above with one-or-more times of occurrences.
  • (([^\]*\\ ){1,})?: this is optional when using (...)?; we could use ([^\]*\\ ){0,} instead as well or ([^\]*\\ )*.
  • ((([^\]*\\ ){1,})?[^ ]*): matches above which is optional followed by anything that it's not a space and hold as group match with \1 as its back-reference.
  • ((([^\]*\\ ){1,})?[^ ]*).*: matches above (...) and anything else .*.

then is replacement part just print the \1 which is the output:

5678
testing,\ group
[testing
ip\ 5.6.7.8
launch-wizard-1
456dlkjfa
1.2.3.4
test
default
launch-wizard-2
launch-wizard-3
2.3.4.5/32

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.