I want to change all the characters in string one by one according to the substitution rule and save them to file on Linux.

This is substitution file (sub.txt).

A -> Y
B -> V
C -> Q

Input file:


first, (A to Y) YBCDEFGHIJ -> save file

second, (B to V) AVCDEFGHIJ -> save file

Which method should I do?

  • 2
    Could you be a little bit more specific in your question please? You will change all the characters (for example all As) or you will change only the first concurrency? You will make the change following any "pattern"? Initially, without additional data, I would recommend using the "sed" command; For example: sed -i 's/A/Y/g' file – Dasel Apr 25 '19 at 13:45
  • i hope after the second edit, your file content should be like, YBCDEFGHIJ . Or do you want to save the changes in two different files? – Siva Apr 25 '19 at 14:12
  • @Dasel I edited the question. I want to change all the characters of string sequentially, and save them as a file. For example, if the string consists of 11 characters, 11 converted files are created. – user2905046 Apr 25 '19 at 14:26
  • @user2905046 Would the input AA give YA then YY or would it jump straight to YY? – Torin Apr 25 '19 at 15:12

Given a sub.txt like this:

$ cat sub.txt 
A -> Y
B -> V
C -> Q
D -> K
E -> L
F -> O
G -> P
H -> W
I -> X
J -> Z

You can iterate over it in a shell loop, reading each of the three elements on each line into a variable:

while IFS=' ' read -r from ignore to; do ... ; done < sub.txt

In that while loop, the $from will be the source character and the $to will be the character you want to replace that with. The $ignore in the middle is just a holder for the ->.

This assumes that space and line feed (' ' and \n) are not in the list of characters you want to transliterate.

With that in mind, you can use tr to make the change and redirect output to a new file:

while IFS=' ' read -r from discard to; do 
    printf '%s\n' "$string" | tr "$from" "$to" > changed."$from".txt
done < sub.txt 

Note that some tr implementations will fail if $from or $to is [ or if they are multi-byte characters. The above also assumes $from is not /.

If string="ABCDEFGHIJ", the command above will create these files:

$ ls changed*
changed.A.txt  changed.D.txt  changed.G.txt  changed.J.txt
changed.B.txt  changed.E.txt  changed.H.txt
changed.C.txt  changed.F.txt  changed.I.txt

With the following contents:

$ for f in changed.*; do printf '%s\n' "=== $f ==="; cat "$f"; done
=== changed.A.txt ===
=== changed.B.txt ===
=== changed.C.txt ===
=== changed.D.txt ===
=== changed.E.txt ===
=== changed.F.txt ===
=== changed.G.txt ===
=== changed.H.txt ===
=== changed.I.txt ===
=== changed.J.txt ===

That changes each character separately. If you instead want to do this incrementally, so the 1st file will only have the 1st character changed, but the second file will have both the 1st and the 2nd characters changed, you can do:

printf '%s\n' "$string" > "$tmpFile" 
while IFS=' ' read -r from ignore to; do 
    tr "$from" "$to" < "$tmpFile" > changed."$from".txt
    cp changed."$from".txt "$tmpFile"
done < sub.txt 

This will create the following files:

$ for f in changed.*; do printf '%s\n' "=== $f ==="; cat "$f"; done
=== changed.A.txt ===
=== changed.B.txt ===
=== changed.C.txt ===
=== changed.D.txt ===
=== changed.E.txt ===
=== changed.F.txt ===
=== changed.G.txt ===
=== changed.H.txt ===
=== changed.I.txt ===
=== changed.J.txt ===
| improve this answer | |

Using sed :

To change two characters one by one in a string,

sed -i 's/A/Y/;s/B/V/' file 

To change and save in different files:

sed 's/A/Y/' file > file1; sed 's/B/V/' file > file1
| improve this answer | |

Done by below method and it worked fine

    awk '{gsub("A","Y",$0);print $0}' l.txt > f_1.txt
    awk '{gsub("B","V",$0);print $0}' l.txt > f_2.txt
    awk '{gsub("C","Q",$0);print $0}' l.txt > f_3.txt
| improve this answer | |
  • I believe you've missed the part where they want the individual edits to be saved into individual files -- and not with all the changes in one file. – Jeff Schaller Apr 25 '19 at 16:11
  • Corrected the code – Praveen Kumar BS Apr 25 '19 at 19:15
  • That's in the right direction; do note that they mention having a substitution file where the ellipsis indicates that there are additional translations... – Jeff Schaller Apr 25 '19 at 19:33

We will do this by making sed work on the sub.txt file to generate a sed code that'll operate on the input to get the various output files, as shown here:

$ sed -ne '
   s|\(.\)[[:blank:]*->[[:blank:]]*\(.\)|g;s/\1/\2/gw ./converted.\1_\2.txt|p
' ./sub.txt | sed -nf - ./input.file

We obtain the output files named as converted.A_Y.txt, converted.B_V.txt, etc. The first sed invocation generates the sed code on the fly based on what transformations are mentioned in the sub.txt input and uses that to run the second sed invocation on the input data.

Assuming the sub.txt file has single character to single character transliteration and the characters are not regex to sed on either the RHS or LHS of s/// command of sed.

| improve this answer | |
  • sed -ne '1i\hs|(.)[[:blank:]*->[[:blank:]]*(.)|g;s/\1/\2/gw ./converted.\1_\2.txt|p ' ./sub.txt | sed -nf - ./input.file Is this correct if the code is in one line? – user2905046 Apr 26 '19 at 6:47
  • No that is not correct. Instead you could do this: sed -ne '1i\h' -e 's|\(.\)[[:blank:]*->[[:blank:]]*\(.\)|g;s/\1/\2/gw ./converted.\1_\2.txt|p' ./sub.txt | sed -nf - ./inp and that too only if you access to GNU sed. The POSIX sed will require an escaped newline like shown in my answer. – Rakesh Sharma Apr 26 '19 at 7:36

I made script based on userinput so mistakes can be avoided

    echo "enter the character need to display"
    read old
    echo "enter the  need character to be replaced"
    read new
    sed "s/$old/$new/g" r.txt>file_$old.txt

First it will ask for old content which need to be replaced. 
Second it will ask for new content which needs to be replaced with old content
THird it saves the file  after each iteration

Based on how  characters need to be replaced you can add above mentioned script in for loop
| improve this answer | |

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.