Home > Blockchain >  'sed: no input files' when using sed -i in a loop
'sed: no input files' when using sed -i in a loop

Time:12-31

I checked some solutions for this in other questions, but they are not working with my case and I'm stuck so here we go. I have a csv file that I want to convert all to uppercase. It has to be with a loop and occupate 7 lines of code minimum. I have to run the script with this command:

./c_bash.sh student-mat.csv

So I tried this Script:

#!/bin/bash
declare -i c=0
while read -r line; do 
    if [ "$c" -gt '0' ]; then 
       sed -e 's/\(.*\)/\U\1/'      
    else
        echo "$line"
    fi
    ((c  ))
done < student-mat.csv

I know that maybe there are a couple of unnecessary things on it, but I want to focus in the sed command because it looks like the problem here. That script shows this output:(first 5 lines):

school,sex,age,address,famsize,Pstatus,Medu,Fedu,Mjob,Fjob,reason,guardian,traveltime,studytime,failures,schoolsup,famsup,paid,activities,nursery,higher,internet,romantic,famrel,freetime,goout,Dalc,Walc,health,absences,G1,G2,G3
GP,F,17,U,GT3,T,1,1,AT_HOME,OTHER,COURSE,FATHER,1,2,0,NO,YES,NO,NO,NO,YES,YES,NO,5,3,3,1,1,3,4,5,5,6
GP,F,15,U,LE3,T,1,1,AT_HOME,OTHER,OTHER,MOTHER,1,2,3,YES,NO,YES,NO,YES,YES,YES,NO,4,3,2,2,3,3,10,7,8,10
GP,F,15,U,GT3,T,4,2,HEALTH,SERVICES,HOME,MOTHER,1,3,0,NO,YES,YES,YES,YES,YES,YES,YES,3,2,2,1,1,5,2,15,14,15
GP,F,16,U,GT3,T,3,3,OTHER,OTHER,HOME,FATHER,1,2,0,NO,YES,YES,NO,YES,YES,NO,NO,4,3,2,1,2,5,4,6,10,10
GP,M,16,U,LE3,T,4,3,SERVICES,OTHER,REPUTATION,MOTHER,1,2,0,NO,YES,YES,YES,YES,YES,YES,NO,5,4,2,1,2,5,10,15,15,15

Now that I see that it works, I want to apply that sed command permanently to the csv file, so I put -i after it:

#!/bin/bash
declare -i c=0
while read -r line; do 
    if [ "$c" -gt '0' ]; then 
       sed -i -e 's/\(.*\)/\U\1/'      
    else
        echo "$line"
    fi
    ((c  ))
done < student-mat.csv

But the output instead of applying the changes, shows this:(first 5 lines)

school,sex,age,address,famsize,Pstatus,Medu,Fedu,Mjob,Fjob,reason,guardian,traveltime,studytime,failures,schoolsup,famsup,paid,activities,nursery,higher,internet,romantic,famrel,freetime,goout,Dalc,Walc,health,absences,G1,G2,G3
sed: no input files
sed: no input files
sed: no input files
sed: no input files
sed: no input files

So checking a lot of different solutions on the internet, I also tried to change single quoting to double quoting.

#!/bin/bash
declare -i c=0
while read -r line; do 
    if [ "$c" -gt '0' ]; then 
       sed -i -e "s/\(.*\)/\U\1/"       
    else
        echo "$line"
    fi
    ((c  ))
done < student-mat.csv

But in this case, instead of applying the changes, it generate a file with 0 bytes. So no output when I do this:

cat student-mat.csv

My expected solution here is that, when I apply this script, it changes permanently all the data to uppercase. And after applying the script, it should show this with the command cat student-mat.csv: (first 5 lines)

school,sex,age,address,famsize,Pstatus,Medu,Fedu,Mjob,Fjob,reason,guardian,traveltime,studytime,failures,schoolsup,famsup,paid,activities,nursery,higher,internet,romantic,famrel,freetime,goout,Dalc,Walc,health,absences,G1,G2,G3
GP,F,17,U,GT3,T,1,1,AT_HOME,OTHER,COURSE,FATHER,1,2,0,NO,YES,NO,NO,NO,YES,YES,NO,5,3,3,1,1,3,4,5,5,6
GP,F,15,U,LE3,T,1,1,AT_HOME,OTHER,OTHER,MOTHER,1,2,3,YES,NO,YES,NO,YES,YES,YES,NO,4,3,2,2,3,3,10,7,8,10
GP,F,15,U,GT3,T,4,2,HEALTH,SERVICES,HOME,MOTHER,1,3,0,NO,YES,YES,YES,YES,YES,YES,YES,3,2,2,1,1,5,2,15,14,15
GP,F,16,U,GT3,T,3,3,OTHER,OTHER,HOME,FATHER,1,2,0,NO,YES,YES,NO,YES,YES,NO,NO,4,3,2,1,2,5,4,6,10,10
GP,M,16,U,LE3,T,4,3,SERVICES,OTHER,REPUTATION,MOTHER,1,2,0,NO,YES,YES,YES,YES,YES,YES,NO,5,4,2,1,2,5,10,15,15,15

Thank you for helping me.

CodePudding user response:

Sed works on files, not on lines. Do not read lines, use sed on the file. Sed can exclude the first line by itself. See sed manual.

You want:

sed -i -e '2,$s/\(.*\)/\U\1/' student-mat.csv

You can do shorter with s/.*/\U&/.


Your code does not work as you think it does. Note that your code removes the second line from the output. Your code:

  • reads first line with read -r line
  • echo "$line" first line is printed
  • c is incremented
  • read -r line reads second line
  • then sed processes the rest of the file (from line 3 till the end) and prints them in upper case
  • then c is incremented
  • then read -r line fails, and the loop exits
  • Related