Insert a line at specific line number with sed or awk

后端 未结 9 1451
佛祖请我去吃肉
佛祖请我去吃肉 2020-11-30 17:15

I have a script file which I need to modify with another script to insert a text at the 8th line.

String to insert: Project_Name=sowstest, into a file c

相关标签:
9条回答
  • 2020-11-30 17:35

    An ed answer

    ed file << END
    8i
    Project_Name=sowstest
    .
    w
    q
    END
    

    . on its own line ends input mode; w writes; q quits. GNU ed has a wq command to save and quit, but old ed's don't.

    Further reading: https://gnu.org/software/ed/manual/ed_manual.html

    0 讨论(0)
  • 2020-11-30 17:35

    Perl solutions:

    quick and dirty:

    perl -lpe 'print "Project_Name=sowstest" if $. == 8' file

    • -l strips newlines and adds them back in, eliminating the need for "\n"
    • -p loops over the input file, printing every line
    • -e executes the code in single quotes

    $. is the line number

    equivalent to @glenn's awk solution, using named arguments:

    perl -slpe 'print $s if $. == $n' -- -n=8 -s="Project_Name=sowstest" file

    • -s enables a rudimentary argument parser
    • -- prevents -n and -s from being parsed by the standard perl argument parser

    positional command arguments:

    perl -lpe 'BEGIN{$n=shift; $s=shift}; print $s if $. == $n' 8 "Project_Name=sowstest" file

    environment variables:

    setenv n 8 ; setenv s "Project_Name=sowstest"
    echo $n ; echo $s
    perl -slpe 'print $ENV{s} if $. == $ENV{n}' file
    

    ENV is the hash which contains all environment variables

    Getopt to parse arguments into hash %o:

    perl -MGetopt::Std -lpe 'BEGIN{getopt("ns",\%o)}; print $o{s} if $. == $o{n}' -- -n 8 -s "Project_Name=sowstest" file

    Getopt::Long and longer option names

    perl -MGetopt::Long -lpe 'BEGIN{GetOptions(\%o,"line=i","string=s")}; print $o{string} if $. == $o{line}' -- --line 8 --string "Project_Name=sowstest" file

    Getopt is the recommended standard-library solution.
    This may be overkill for one-line perl scripts, but it can be done

    0 讨论(0)
  • 2020-11-30 17:40

    For those who are on SunOS which is non-GNU, the following code will help:

    sed '1i\^J
    line to add' test.dat > tmp.dat
    
    • ^J is inserted with ^V+^J
    • Add the newline after '1i.
    • \ MUST be the last character of the line.
    • The second part of the command must be in a second line.
    0 讨论(0)
  • 2020-11-30 17:42

    sed -i "" -e $'4 a\\n''Project_Name=sowstest' start

    • This line works fine in macOS
    0 讨论(0)
  • 2020-11-30 17:43

    sed -e '8iProject_Name=sowstest' -i start using GNU sed

    Sample run:

    [root@node23 ~]# for ((i=1; i<=10; i++)); do echo "Line #$i"; done > a_file
    [root@node23 ~]# cat a_file
    Line #1
    Line #2
    Line #3
    Line #4
    Line #5
    Line #6
    Line #7
    Line #8
    Line #9
    Line #10
    [root@node23 ~]# sed -e '3ixxx inserted line xxx' -i a_file 
    [root@node23 ~]# cat -An a_file 
         1  Line #1$
         2  Line #2$
         3  xxx inserted line xxx$
         4  Line #3$
         5  Line #4$
         6  Line #5$
         7  Line #6$
         8  Line #7$
         9  Line #8$
        10  Line #9$
        11  Line #10$
    [root@node23 ~]# 
    [root@node23 ~]# sed -e '5ixxx (inserted) "line" xxx' -i a_file
    [root@node23 ~]# cat -n a_file 
         1  Line #1
         2  Line #2
         3  xxx inserted line xxx
         4  Line #3
         5  xxx (inserted) "line" xxx
         6  Line #4
         7  Line #5
         8  Line #6
         9  Line #7
        10  Line #8
        11  Line #9
        12  Line #10
    [root@node23 ~]# 
    
    0 讨论(0)
  • 2020-11-30 17:46

    POSIX sed (and for example OS X's sed, the sed below) require i to be followed by a backslash and a newline. Also at least OS X's sed does not include a newline after the inserted text:

    $ seq 3|gsed '2i1.5'
    1
    1.5
    2
    3
    $ seq 3|sed '2i1.5'
    sed: 1: "2i1.5": command i expects \ followed by text
    $ seq 3|sed $'2i\\\n1.5'
    1
    1.52
    3
    $ seq 3|sed $'2i\\\n1.5\n'
    1
    1.5
    2
    3
    

    To replace a line, you can use the c (change) or s (substitute) commands with a numeric address:

    $ seq 3|sed $'2c\\\n1.5\n'
    1
    1.5
    3
    $ seq 3|gsed '2c1.5'
    1
    1.5
    3
    $ seq 3|sed '2s/.*/1.5/'
    1
    1.5
    3
    

    Alternatives using awk:

    $ seq 3|awk 'NR==2{print 1.5}1'
    1
    1.5
    2
    3
    $ seq 3|awk '{print NR==2?1.5:$0}'
    1
    1.5
    3
    

    awk interprets backslashes in variables passed with -v but not in variables passed using ENVIRON:

    $ seq 3|awk -v v='a\ba' '{print NR==2?v:$0}'
    1
    a
    3
    $ seq 3|v='a\ba' awk '{print NR==2?ENVIRON["v"]:$0}'
    1
    a\ba
    3
    

    Both ENVIRON and -v are defined by POSIX.

    0 讨论(0)
提交回复
热议问题