Search code examples
linuxbashshellsed

linux command to prefix a value for all lines in a file except for first line and lines starting with hash symbol


Given a file input.csv as shown below,

EMP_ID,EMP_NAME,JOINING_DATE,SALARY
1,T Natarajan,22-APR-2024,6000000
2,Velmurugan,22-JUL-2024,2000000
3,Rowin,21-OCT-2024,5000000
#END_OF_FILE

how to prefix "E_" to all lines except for first line and lines starting with hash symbol (#). The expected output is,

EMP_ID,EMP_NAME,JOINING_DATE,SALARY
E_1,T Natarajan,22-APR-2024,6000000
E_2,Velmurugan,22-JUL-2024,2000000
E_3,Rowin,21-OCT-2024,5000000
#END_OF_FILE

Tried this command sed -i -E '/^(#)/! s/^/E_/' input.csv but it's updating the 1st line as well.


Solution

  • You are doing nothing to exclude the first line.

    You can combine two conditions with braces:

    sed '/^#/!{;1!s/^/E_/;}' input.csv
    

    or perhaps

    sed '2,${;/^#/!s/^/E_/;}' input.csv
    

    or you can turn around the logic to skip those lines;

    sed '/^#/b;1b;s/^/E_/' input.csv
    

    (The b command says "jump to this point in the script"; without a label, it jumps to the end, skipping the rest of the script for the current input line.)

    I took out the -i option; put it back once you are satisfied that the results match your expectation.

    Also, the parentheses were not contributing anything, so I removed them too. With that, the script no longer uses any ERE syntax, so I took out the -E option as well.

    The semicolons next to the braces are optional in some dialects, but probably necessary in others.

    If you want this in Awk instead, that should be easy.

    awk 'FNR > 1 && !/^#/ { sub(/^/, "E_") } 1' file >newfile
    

    Standard Awk does not have any option like the -i option in (non-standard) sed; but GNU Awk offers -i inplace