30

Is there a way to print all records separated by the OFS without typing out each column number.

#Desired style of syntax, undesired result
[kbrandt@glade: ~] echo "1 2 3 4" | gawk 'BEGIN { OFS=" :-( "}; {print $0}'        
1 2 3 4

#Desired result, undesired syntax
[kbrandt@glade: ~] echo "1 2 3 4" | gawk 'BEGIN { OFS=" :-) "}; {print $1,$2,$3,$4}'
1 :-) 2 :-) 3 :-) 4
Kyle Brandt
  • 26,938
  • 37
  • 124
  • 165

2 Answers2

44

This is a variation on the first style:

echo "1 2 3 4" | gawk 'BEGIN { OFS=" :-( "}; {$1=$1; print $0}'

Results:

1 :-( 2 :-( 3 :-( 4

Explanation:

the $1=$1 is to rebuild the record, using the current OFS (you can also see http://www.gnu.org/software/gawk/manual/gawk.html#Changing-Fields)

Update:

(suggested by @EdMorton and @steve) This is a briefer, equivalent version of the awk command, that sets OFS in the command line, and takes advantage of print $0 as the default action:

awk -v OFS=" :-( " '{$1=$1}1'
German Garcia
  • 1,209
  • 14
  • 14
  • @steve note: there was one edit that replaced the block `{$1=$1; print $0}` with just `$1=$1`. That would fail for $1 == 0. – German Garcia Dec 04 '12 at 15:34
  • @EdMorton that's a perfectly valid alternative (`awk -v OFS=" :-( " '{$1=$1}1'`. I still like the first version 'cause it's so similar to the OP's (and I don't see any clear advantage of one over the other, mostly a question of style maybe) – German Garcia Dec 04 '12 at 20:40
  • @GermanGarcia: Wasn't that the _exact_ edit that I made? Personally I think `awk -v OFS=" :-( " '{$1=$1}1` is clearer, but the only reason I decided to edit was because users won't actually need `GNU awk` specifically. The command should work of other `awks` too. If we were trying to make things shorter, we could still go further: `awk '{$1=$1}1' OFS=" :-( "`. HTH. – Steve Dec 04 '12 at 22:30
  • @GermanGarcia I slightly prefer the briefer version in this case as it re-inforces the concepts of using -v to assign initial values to variables and of "print $0" being the default action which are both things that if you're experienced you'll have no problem understanding and would probably naturally use and if you're inexperienced you really need to get familiar with ASAP so IMHO it had benefits for both experienced and inexperienced awk users. No big deal either way though. – Ed Morton Dec 04 '12 at 23:55
  • You could do away with the block and go one char shorter with the slightly more obscure: `$1=$1;1`. – Thor Dec 05 '12 at 09:12
  • @steve No, it was not your exact edit. You can see your edit here: http://stackoverflow.com/revisions/13705660/2 (it uses only the condition `$1=$1`, leaving the action part empty; but that introduces the problem of being a false condition for $1 == 0). Regarding the briefer version, I'll add that in a moment. Thanks for your comments. – German Garcia Dec 05 '12 at 14:09
  • @EdMorton I've updated the answer to include the briefer version suggested by you and steve, so as to take those concepts into account. – German Garcia Dec 05 '12 at 15:51
  • 2
    @Thor `$1=$1;1` will print every line that has a non-zero/null $1 value twice which probably isn't desired. You could do `$1=$1,1` but as we discovered recently no-one knows what that means without some investigation so it should be avoided :-). – Ed Morton Dec 05 '12 at 20:58
  • @GermanGarcia: It seems you were right! I must have forgotten to have added that `1` on the end. I blame lack of sleep ... but there's no excuse is there? – Steve Dec 05 '12 at 22:40
  • @EdMorton: doh, ignore my suggestion. Btw, `$1=$1,1` doesn't work here with gawk, it evaluates to false. Anyway the briefest clear version has already been posted. – Thor Dec 06 '12 at 00:25
  • @steve I always reserve myself one more excuse, just in case :) Regards – German Garcia Dec 07 '12 at 04:30
  • For some reason, this solution prints two OFS after the first record. (I can move the doubled-up OFS if I replace `$1=$1` with say `$10=$10`). Any explanation? I *can* get rid of it if I do "{$NF=$NF}1" – davemyron Jun 04 '15 at 01:11
  • @davemyron I could not reproduce the behavior you mention (tried original awk, mawk and gawk). What version of awk are you using? Can you give a little example? – German Garcia Jun 05 '15 at 11:51
  • @GermanGarcia I ran into the issue when using an FPAT for comma-separated values: `awk -v FPAT='[^,]*|"[^"]*"' -v OFS='|' '{$1=$1}1' <(echo "comma,separated,values")` results in `comma||separated|values` – davemyron Jun 09 '15 at 21:39
  • @davemyron I've tried your sample and it does indeed print those two OFS after the first field (precisely after the $N field, except when N==NF as you already mentioned) when using FPAT. I don't know why gawk acts this way (IMHO this seems to be a bug, and using $NF=$NF as you suggest may act as a workaround) Also, it seems to work fine if you use [^,]+ instead of [^,]* ..but now you can't have empty fields inside commas – German Garcia Jun 25 '15 at 20:33
  • Since the question is about `OFS = "something"` being effective in the output and assumes nothing about other system variables being changed as well, I'd like to add that if one sets `FS = "\n"` as well in the `BEGIN` rule, `$1 = $1` is obviously not enough, since it is also needed to set `RS = ""` in the `BEGIN` rule. (Indeed, I've hit this question while trying to use `awk` to join all lines of a file, since simply setting `FS = "\n"` and `OFS = " "` didn't seem to work.) – Enlico Apr 15 '18 at 10:47
2

Sed equivalent:

$ echo "1 2 3 4" | sed 's/ /:-)/g'

Here's another option with awk:

$ echo "1 2 3 4" | awk '{ gsub(/\s/, ":-)")}1' 
Fred Hicks
  • 21
  • 2
  • 1
    Welcome to SO! The question asks about awk specifically. So an answer using sed is out of place here. – cfi Sep 21 '14 at 23:24
  • I think you sed should read `sed 's/ / :-) /g'` if you notice, the OP had a space around the smiley in the OFS – v010dya Oct 09 '15 at 04:48