52

Can tr replace one character with two characters?

I am trying to replace "~" with "~\n" but the output does not produce the newline.

$ echo "asdlksad ~ adlkajsd ~ 12345" | tr "~" "~\n"
asdlksad ~ adlkajsd ~ 12345
Danilo Favato
  • 283
  • 1
  • 11
Paolo
  • 1,557
  • 3
  • 18
  • 28

5 Answers5

46

No, tr is specifically intended to replace single characters by single characters (or, depending on command-line options, to delete characters or replace runs of a single character by one occurrence.).

sed is probably the best tool for this particular job:

$ echo "asdlksad ~ adlkajsd ~ 12345" | sed 's/~/~\n/g'
asdlksad ~
 adlkajsd ~
 12345

(Note that this requires sed to interpret the backlash-n \n sequence as a newline character. GNU sed does this, but POSIX doesn't specify it except within a regular expression, and there are definitely older versions of sed that don't.)

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
7

you could go with awk, let FS/OFS variable do the job for you:

awk -F'~' -v OFS="~\n" '$1=$1' 

test with your example:

kent$ awk -F'~' -v OFS="~\n" '$1=$1' <<< "asdlksad ~ adlkajsd ~ 12345" 
asdlksad ~
 adlkajsd ~
 12345
Kent
  • 189,393
  • 32
  • 233
  • 301
  • 2
    This solved a problem for me, but it was not clear to me what was happening, so I dug a little deeper for some clarity: "-F" == "input field separator" and "-OFS" == "output field separator" (the trick here being that the "OFS" can be multi-character) and the "<<<" passes the quoted string to awk as STDIN (in the same shell) - this avoids the issue with pipes where the transaction is done in a different sub-shell. – netDesign8 Apr 10 '20 at 19:33
7

tr can only do 1 to 1 translation.

Here is one way of doing that using pure Bash:

s='"asdlksad ~ adlkajsd ~ 12345'
r=$'~\n'
echo -e "${s//\~/$r}"
asdlksad ~
 adlkajsd ~
 12345
anubhava
  • 761,203
  • 64
  • 569
  • 643
2

no can do, sorry.

tr is meant to transliterate one character with another.

there are numerous options, but I would use awk, i.e.

echo "asdlksad ~ adlkajsd ~ 12345" | awk '{gsub(/[~]/, "&\n")};1'

output

asdlksad ~
 adlkajsd ~
 12345
anubhava
  • 761,203
  • 64
  • 569
  • 643
shellter
  • 36,525
  • 7
  • 83
  • 90
  • Instead of `/[~]/`, the shorter form `/~/` also works. The `;1` at the end is not necessary. (Or is it, for some obscure old operating system?) – Roland Illig Dec 08 '18 at 06:43
0
echo "asdlksad ~ adlkajsd ~ 12345" | sed 's/~/~|/g' | tr '|' '\n'

--This will work perfect, since sed having a problem replacing \n

Sourabh Kumar Sharma
  • 2,864
  • 3
  • 25
  • 33
Samanway
  • 17
  • 1