15

I have been through the sed one liners but am still having trouble with my goal. I want to substitue matching strings on all but the first occurrence of a line. My exact usage would be:

 $ echo 'cd /Users/joeuser/bump bonding/initial trials' | sed <<MAGIC HAPPENS>
 cd /Users/joeuser/bump\ bonding/initial\ trials

The line replaced the space in bump bonding with the slash space bump\ bonding so that I can execute this line (since when the spaces aren't escaped I wouldn't be able to cd to it).

Update: I solved this by just using single quotes and outputting

 cd 'blah blah/thing/another space/'

and then using source to execute the command. But it didn't answer my question. I'm still curious though... how would you use sed to fix it?

Dennis Williamson
  • 346,391
  • 90
  • 374
  • 439
physicsmichael
  • 4,793
  • 11
  • 35
  • 54

3 Answers3

18
s/ /\\ /2g

The 2 specifies that the second one should apply, and the g specifies that all the rest should apply too. (This probably only works on GNU sed. According to the Open Group Base Specification, "If both g and n are specified, the results are unspecified.")

C. K. Young
  • 219,335
  • 46
  • 382
  • 435
  • 1
    You are correct about the GNU sed. On my Mac it doesn't work. But this is the exact kind of elegant solution I was looking for. – physicsmichael Jan 30 '10 at 00:58
  • 2
    @physicsmichael You can install GNU sed on a Mac with `brew install gsed`. After installation, you can type the command as `/usr/local/bin/gsed` instead of `sed`. – stacko Dec 30 '16 at 17:28
16

You can avoid the problem with g and n

Replace all of them, then undo the first one:

sed -e 's/ /\\ /g' -e 's/\\ / /1'

Here's another method which uses the t branch-if-substituted command:

sed ':a;s/\([^ ]* .*[^\\]\) \(.*\)/\1\\ \2/;ta'

which has the advantage of leaving existing backslash-space sequences in the input intact.

Dennis Williamson
  • 346,391
  • 90
  • 374
  • 439
  • 1
    Your first answer looks to be the universal solution. With a little reading, the -e flag seems to be what I was really looking for. – physicsmichael Jan 30 '10 at 22:56
1

use awk

$ echo cd 'blah blah/thing/another space/' | awk '{for(i=2;i<NF;i++) $i=$i"\\"}1'
cd blah\ blah/thing/another\ space/

$ echo 'cd /Users/joeuser/bump bonding/initial trials' | awk '{for(i=2;i<NF;i++) $i=$i"\\"}1'
cd /Users/joeuser/bump\ bonding/initial\ trials
ghostdog74
  • 327,991
  • 56
  • 259
  • 343