I read a file line by line and edit each line and save those lines in a separate file.

while read -r line
   newline=$(echo $line | sed -r 's/\</\n/g' | sort | tr '\n' ' ')
   echo "$newline" >> newfile
done < "$filename"

But I want to replace the original lines with respect to $filename with the new lines. I read that I could use cat filename... | xargs -n1 command or sed -i ... but till now my trails are failed.

Here is an example input:

1.e4 e5 2.Nf3 Nc6 3.
1.d4 d5 2.e4 dxe4 3.
1.e4 e5 2.Nf3 Nf6 3.

and this is the expected output:

 1. 2. 3. e4  e5  Nc6  Nf3  
 1. 2. 3. d4  d5  dxe4  e4  
 1. 2. 3. e4  e5  Nf3  Nf6 

2 Answers 2


You could use sponge, as mentioned in A program that could buffer stdin or file. You can pipe the whole loop to it, in the same way the input is redirected to it:

while read -r line ; do 
    echo "$line" | sed -r 's/\</\n/g' | sort | tr '\n' ' ' ; 
done < filename | sponge filename

With Perl, the same could be done with this (the amount of whitespace is different):

perl -Mlocale -i -lne 'print join " ", sort split/(?<=\.)| /' filename
  • @steeldriver, ah you're quite right, thanks!
    – ilkkachu
    Apr 12, 2017 at 20:37

awk approach:

awk 'BEGIN{IGNORECASE=1;}{ gsub(/\./,". ", $0); split($0, w, " "); 
     asort(w);l=""; for(i in w) {l=l" "w[i]} print l}' file

The output:

1. 2. 3. e4 e5 Nc6 Nf3
1. 2. 3. d4 d5 dxe4 e4
1. 2. 3. e4 e5 Nf3 Nf6

IGNORECASE can be set on the command line or in a BEGIN rule

split($0, w, " "); - splits the line into separate words

asort(w); - sorts array values(words)

for(i in w) {l=l" "w[i]} - concatenating sorted words into a single line

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .