9
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
4
  • Is \ being treated as an escape character always or is only \ special? For instance, is a\\ b one field or two? Sep 25, 2018 at 23:49
  • @GregoryNisbet I've put in \ is for escape character, not the real data Sep 26, 2018 at 0:13
  • 1
    If your data happened to contain a real backslash, how would it be represented? Sep 26, 2018 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 \. Sep 26, 2018 at 0:31

4 Answers 4

9

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,
5

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

sed 's/\\ /\\x20/g' data_file | awk '{ print $1; }' | sed 's/\\x20/\\ /g'
2
  • Only with sed : sed 's/\\ /\\x20/g;s/ .*//;s/\\x20/\\ /g' data_file
    – ctac_
    Sep 25, 2018 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 Sep 25, 2018 at 18:29
5

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\\.

4

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

You must log in to answer this question.

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