Ubuntu – How to replace a string on the 5th line of multiple text files

bashcommand linetext processing

I want to replace the 5th line of multiple text files (file1.txt,file2.txt,file3.txt,file4.txt) with the string " Good Morning " using a single terminal command.

All the text files are located on my ~/Desktop.

Note: My desktop consists of 6 .txt files.I want to apply the change to above mentioned 4 text files only.

Best Answer

Here are a few approaches. I am using brace expansion (file{1..4}.txt) which means file1.txt file2.txt file3.txt file4.txt

  1. Perl

    perl -i -pe 's/.*/ Good Morning / if $.==5' file{1..4}.txt
    

    Explanation:

    • -i: causes perl to edit the files in place, changing the original file.

      If -i is followed with a file extension suffix, then a backup is created for every file that is modified. Ex: -i.bak creates a file1.txt.bak if file1.txt is modified during the execution.

    • -p: means read the input file line by line, apply the script and print it.

    • -e: allows you to pass a script from the command line.

    • s/.*/ Good Morning /: That will replace the text in the current line (.*) with Good Morning.

    • $. is a special Perl variable that holds the current line number of the input file. So, s/foo/bar/ if $.==5, means replace foo with bar only on the 5th line.

  2. sed

    sed -i '5s/.*/ Good Morning /' file{1..4}.txt
    

    Explanation:

    • -i: Like for perl, edit file in place.

    By default, sed prints each line of the input file. The 5s/pattern/replacement/ means substitute pattern with replacement on the 5th line.

  3. Awk

    for f in file{1..4}.txt; do 
        awk 'NR==5{$0=" Good Morning "}1;' "$f" > foobar && mv foobar "$f"; 
    done
    

    Explanation:

    awk has no equivalent to the -i option¹ which means that we need to create a temporary file (foobar) which is then renamed to overwrite the original. The bash loop for f in file{1..4}.txt; do ... ; done simply goes through each of file{1..4}.txt, saving the current file name as $f. In awk, NR is the current line number and $0 is the content of the current line. So, the script will replace the line ($0) with " Good Morning " only on the 5th line. 1; is awk for "print the line".

    ¹Newer versions do as devnull showed in his answer.

  4. coreutils

    for f in file{1..4}.txt; do 
        (head -4 "$f"; echo " Good Morning "; tail -n +6 "$f") > foobar && 
        mv foobar "$f"; 
    done 
    

    Explanation:

    The loop is explained in the previous section.

    • head -4: print the first 4 lines

    • echo " Good Morning ": print " Good Morning "

    • tail -n +6: print everything from the 6th line to the end of the file

    The parentheses ( ) around those three commands allow you to capture the output of all three (so, 1st 4 lines, then " Good morning ", then the rest of the lines) and redirect them to a file.