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 

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 '17 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

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.