简体   繁体   中英

Linux: Extract the first line of a file

I am working with OpenWrt and a very small amount of space.

Trying to extract the first line from a file. The line needs to go into a variable and be removed from the file. I can use head to put it into a variable but can't use tail because as far as I understand I would have to do tail file > newFile and I do not have room for that second file.

Does some one know if a better technic?

使用

sed -i -e '1 w /dev/stdout' -e '1d' file

Edit: you can't use my old answer (see below) with OpenWrt since OpenWrt doesn't ship with ed . What a shame. So here are two methods:

The vi way

vi is a genuine editor too, so the following will work:

vi -c ':1d' -c ':wq' file > /dev/null

We open the file with vi , and use the commands :1d to delete the first line and :wq to save and quit, redirecting all output to /dev/null . Cool, clean, short and simple.

Oh, you will of course run:

firstline=$(head -n1 file)

before running this vi command to get the first line of the file into the variable firstline .

Note. On a system with very little memory, and when file is huge, this method fails.

The dd way

dd is a cool tool for this. The dd methods given in other answers are really great, yet they rely on the truncate utility which does not ship with OpenWrt. Here's a workaround:

firstline=$(head -n1 file)
linelength=$(head -n1 file | wc -c)
newsize=$(( $(wc -c < file) - $linelength ))
dd if=file of=file bs=1 skip=$linelength conv=notrunc
dd if=/dev/null of=file bs=1 count=0 seek=$newsize

This will work even with huge files and very little memory! The last dd command plays the role of the truncate command given in the other answers.


Old answer was:

You can use ed for this:

firstline=$(printf '%s\n' 1p d wq | ed -s file.txt)

At each call, you'll get the first line of the file file.txt in the variable firstline , and this line is removed from the file.

Show first line and delete it:

 head -1 file
 sed -i 1d file

This does, however, implicitly create a temporary file. A better solution could be sponge as pointed out in this article about “In-place” editing of files .

I wouldn't call it elegant, but here is a potential way:

# Find the number of characters in the first line
BYTES=$(head -n 1 file | wc -c)
# Shift all the data in-place
dd if=file of=file bs=1 skip=$BYTES conv=notrunc
# Remove the extra bytes on the end
truncate -s -$BYTES file

There are no standard utilities (except of dd ) to modify a file inplace without any temporary file.

One solution which might work is:

LINELENGTH=$(head -1 test.txt | wc -c)
tail -n +2 test.txt | dd of=test.txt conv=notrunc
truncate -s -$LINELENGTH test.txt

See https://unix.stackexchange.com/a/11074/15241 for discussion of this topic.

EDIT:

As the file is downloaded first with curl (see comments). There is another option:

curl URL | sed -e "1w first_line.txt" -e "1d" > rest.txt
firstline=$(cat first_line.txt)
rm first_line.txt

If you have enough ram:

contents=$(cat file) 
echo "$contents" | sed -n '1 !p' > file

Alternatively, use ed:

ed file
2,$wq

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