lajarre
lajarre

Reputation: 5162

Replace one character by the other (and vice-versa) in shell

Say I have strings that look like this:

$ a='/o\\'
$ echo $a
/o\
$ b='\//\\\\/'
$ echo $b
\//\\/

I'd like a shell script (ideally a one-liner) to replace / occurrences by \ and vice-versa.

Suppose the command is called invert, it would yield (in a shell prompt):

$ invert $a
\o/
$ invert $b
/\\//\

For example using sed, it seems unavoidable to use a temporary character, which is not great, like so:

$ echo $a | sed 's#/#%#g' | sed 's#\\#/#g' | sed 's#%#\\#g'
\o/
$ echo $b | sed 's#/#%#g' | sed 's#\\#/#g' | sed 's#%#\\#g'
/\\//\

For some context, this is useful for proper printing of git log --graph --all | tac (I like to see newer commits at the bottom).

Upvotes: 0

Views: 717

Answers (4)

Daweo
Daweo

Reputation: 36630

If you are strictly limited to GNU AWK you might get desired result following way, let file.txt content be

\//\\\\/

then

awk 'BEGIN{FPAT=".";OFS="";arr["/"]="\\";arr["\\"]="/"}{for(i=1;i<=NF;i+=1){if($i in arr){$i=arr[$i]}};print}' file.txt

gives output

/\\////\

Explanation: I inform GNU AWK that field is any single character using FPAT built-in variable and that output field separator (OFS) is empty string and create array where key-value pair represent charactertobereplace-replacement, \ needs to be escaped hence \\ denote literal \. Then for each line I iterate overall all fields using for loop and if given field hold character present in array arr keys I do exchange it for corresponding value, after loop I print line.

(tested in gawk 4.2.1)

Upvotes: 1

Benjamin W.
Benjamin W.

Reputation: 52361

If you want to replace every instance of / with \, you can uses the y command of sed, which is quite similar to what tr does:

$ a='/o\'
$ echo "$a"
/o\
$ echo "$a" | sed 'y|/\\|\\/|'
\o/
$ b='\//\\/'
$ echo "$b"
\//\\/
$ echo "$b" | sed 'y|/\\|\\/|'
/\\//\

Upvotes: 1

Norman Gray
Norman Gray

Reputation: 12514

tr is your friend:

% echo 'abc' | tr ab ba      
bac
% echo '/o\' | tr '\\/' '/\\'
\o/

(escaping the backslashes in the output might require a separate step)

Upvotes: 3

Luuk
Luuk

Reputation: 14948

I think this can be done with (g)awk:

$ echo a/\\b\\/c | gawk -F "/" 'BEGIN{ OFS="\\" } { for(i=1;i<=NF;i++) gsub(/\\/,"/",$i); print $0; }'
a\/b/\c
$ echo a\\/b/\\c | gawk -F "/" 'BEGIN{ OFS="\\" } { for(i=1;i<=NF;i++) gsub(/\\/,"/",$i); print $0; }'
a/\b\/c
$
  • -F "/" This defines the separator, The input will be split in "/", and should no longer contain a "/" character.
  • for(i=1;i<=NF;i++) gsub(/\\/,"/",$i);. This will replace, in all items in the input, the backslash (\) for a slash (/).

Upvotes: 1

Related Questions