简体   繁体   中英

How to write to first n lines of file in bash

I have a file test.txt with following content

first
second
AAA
BBB
CCC
DDD

And I want to remove the first two lines and add new values to the first two lines,

so,

once the first two lines are removed, file should look like this:

AAA
BBB
CCC
DDD

And then should add the two values to first line and then the second line, so the file would finally look like below:

new value at line 1
new value at line 2
AAA
BBB
CCC
DDD

So I tried the below command, but how can I remove the first two lines?

SERVER_HOSTNAME=$(hostname)
SERVER_IP=$(ip -o route get to 8.8.8.8 | sed -n 's/.*src \([0-9.]\+\).*/\1/p')
sed -i "1s/.*/$SERVER_HOSTNAME/" /tmp/test.txt
sed -i "2s/.*/$SERVER_IP/" /tmp/test.txt

My problem is, when I first remove the first two lines, and execute the above command, it will replace the line number 1 and two with new values, but I want to add them on the top so the others (already existing content will shift down) will go down.

Could you please try following, written and tested with shown samples in GNU awk . This will edit 1st and 2nd lines with shell variable values and do an inplace save into Input_file itself.

In case you want to keep 1st line's content as well as print current content then one could remove next in FNR==2 OR FNR==1 conditions.

SERVER_HOSTNAME=$(hostname)
SERVER_IP=$(ip -o route get to 8.8.8.8 | sed -n 's/.*src \([0-9.]\+\).*/\1/p')
awk -v server_ip="$SERVER_IP" -v server_hostname="$SERVER_HOSTNAME" '
FNR==1{ print server_hostname; next}
FNR==2{ print server_ip;     ; next}
1
' Input_file > temp && mv temp Input_file

Explanation for above solution:

awk -v server_ip="$SERVER_IP" -v server_hostname="$SERVER_HOSTNAME" '
##Starting awk program from here, creating server_ip and server_hostname vars with respective shell vars.
FNR==1{ print server_hostname; next}
##Checking condition if this is 1st line then print server_hostname.
FNR==2{ print server_ip;     ; next}
##Checking condition if this is 2nd line then print server_ip here.
1
##1 will print current line.
' Input_file
##Mentioning Input_file name here.

Don't run sed -i repeatedly. Instead, combine all your commands into one script.

sed -i "1s/.*/$(hostname)/
    2s/.*/$(ip -o route get to 8.8.8.8)/
    2s/.*src \([0-9.]\+\).*/\1/" /tmp/test.txt

This is rather brittle, though; in particular, it will break if either of the command substitutions produces a slash in their output.

(IIRC ip has options to produce machine-readable output; you should probably look into that instead of replacing out the parts you don't want.)

If you want to add, then delete, the sed d and a commands do that, respectively. But removing two and adding two is obviously equivalent to replacing two.

sed -i "1d
1a\hello
2d
2a\hello" file

Unfortunately, the a command is poorly standardized, and it's unclear how two s commands would not work, so I'm leaving this as a sketch.

Your existing sed already does what you want; it doesn't need you to remove the first two lines yourself first.

$ cat tmp.txt
first
second
AAA
BBB
CCC
DDD
$ SERVER_HOSTNAME=example.local
$ SERVER_IP=127.0.0.1
$ sed -i "1s/.*/$SERVER_HOSTNAME/;2s/.*/$SERVER_IP/" tmp.txt
$ cat tmp.txt
example.local
127.0.0.1
AAA
BBB
CCC
DDD

You may use this gnu sed :

gsed -i -e "1i\\$SERVER_HOSTNAME\n$SERVER_IP" -e '1,2{d;q;}' /tmp/test.txt

Or using POSIX sed:

sed -i.bak "1,2{d;q;};3i\\
$SERVER_HOSTNAME
3i\\
$SERVER_IP
" /tmp/test.txt

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM