1

Given a pattern of the form:

a\b\c\d:text\text

how can I use sed to output

a/b/c/d:text\text

that is, given a path using backslashes followed by a colon followed by arbitrary text, how do I replace only the backslashes preceding the colon with forward slashes?

1
  • So, the a\b\c\d is just an example? The path (the string to the left of the colon) could be \a\b or e\f\g\h\j\k\l?
    – Scott
    Aug 23 '17 at 2:42
3

Using awk rather than sed:

awk -v FS=':' -v OFS=':' '{ gsub(/\\/,"/",$1) } { print }'

This treats the data as a :-delimited record and uses gsub() to replace all backslashes with forward slashes in the first field. It then outputs the modified data.

I set both the input field separator (FS) and the output field separator (OFS) to : so that the input is split on the colon and so that the colon is later inserted again when the output happens.


If you have the text in a shell variable, you may do this directly in the shell without using any external utilities too:

a='a\b\c\d:text\text'
b=${a%%:*}  # the start of the string ("remove the first : and everything after it from $a")
c=${a#*:}   # the end of the string ("remove the first : and everything before it from $a")

a="${b//\\//}:$c"

printf '%s\n' "$a"

This code snippet will print the string a/b/c/d:text\text in any sh-shell that supports the parameter expansion ${parameter//pattern/string} (an extension to the POSIX standard).

This is more or less mimicking the awk code.

6
  • With your Awk script in single quotes as shown, you should not need quadruple backslashing ever. The shell will not try to interpret or further parse anything in single quotes. Can you double check what happened?
    – Wildcard
    Aug 23 '17 at 6:44
  • @Wildcard That's what I thought too. So the reason I'm repeating it 4 times is that I get the wrong results (except with mawk). That means that it might be something else other than the shell that requires the extra quoting in gawk and nawk.
    – Kusalananda
    Aug 23 '17 at 6:47
  • 1
    Ah, digging through the POSIX specs, I see that "all string literals are subject to lexical analysis, which would reduce each pair of <backslash> characters to a single <backslash> before being passed to gsub." So you're running into this because you're passing a string literal as a pattern rather than a literal ERE. Using gsub(/\\/,"/",$1) should work on any Awk. (I'd love it if you could verify; I don't have all those versions you mention.)
    – Wildcard
    Aug 23 '17 at 6:49
  • @Wildcard Nicely! Thanks for that! Turns out mawk was doing it wrong then, which is odd. I don't know why I used a string literal there...
    – Kusalananda
    Aug 23 '17 at 6:53
  • 1
    (1) Regarding backslashes in gsub calls in awk, see The GNU Awk User’s Guide Gory Details — More about ‘\’ and ‘&’ with sub(), gsub(), and gensub(). (2) In your second solution, I believe that you need b=${a%%:*}, because the delimiter is (presumably) the first colon.  Since the OP says that the text after the colon delimiter is arbitrary, it could include additional colon(s); e.g., a\b\c\d:foo:bar.
    – Scott
    Aug 23 '17 at 20:20
2

A few ways to do this; here is one:

sed -e ':a' -e 's_^\([^:]*\)\\_\1/_;t a'

Explanation breadcrumbs:

-e specifies an editing command. There are two such commands here.

:a defines a label which can be used in "goto" statements.

The s command replaces the first backslash on the line with a forward slash, as long as the first backslash occurs before any colon character.

The t a command branches to the :a label providing a substitution was successfully made with the s command. (Conditional "goto.")

1
  • @Scott, if you check my profile and look at my Sed and Awk answers, you will see that I am sometimes given to very verbose explanations. (Example.) But, I don't feel obliged to write those in every instance. I will add a brief explanation, since you asked; feel free to expand it.
    – Wildcard
    Aug 23 '17 at 3:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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