Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bash: pop lines in a file [closed]

Tags:

bash

line

I need to read a file with bash and remove the request line? Some similar to pop/push functions.

How can i do it?

like image 224
Rfraile Avatar asked Dec 10 '12 16:12

Rfraile


1 Answers

Right! sed would do the job finely!

Intro

As rightly pointed by a comment from @Lee Netherton, the when running sed for inplace editing, the use of backups are strongly recommended! (Of course, once done, your script have to test the success of sed command before continuing... )

Test case

So let quickly build a test file:

printf "Line #%2d\n" {1..7} >file

for pop (from top of stack):

As a real push/pop, the following command return the wanted line and drop them from the named file.

sed -e \$$'{w/dev/stdout\n;d}' -i~ file
Line # 7

then

cat file
Line # 1
Line # 2
Line # 3
Line # 4
Line # 5
Line # 6

for shift (from bottom of stack):

sed -e 1$'{w/dev/stdout\n;d}' -i~ file
Line # 1

for splice (random access in stack)

(removing nth line)

lineNum=3
sed -e $lineNum$'{w/dev/stdout\n;d}' -i~ file
Line # 4

for push (to top of stack):

printf -v val "Line #%2d" 28
echo "$val" >>file

Nota: This could be done by using sed anyway:

sed -e "\$a$val" -i~ file

(Where $a IS NOT a variable, but the sed location $, which mean at end of file and the a command, which mean append after current line)

for unshift (to bottom of stack):

printf -v val "Line #%2d" 62
sed -e 1i"$val" -i~ file

Then finally

cat file
Line #62
Line # 2
Line # 3
Line # 5
Line # 6
Line #28

Into a variable

Of course, the goal is to retrieve them into a variable. Depending of if you are using bash or another POSIX shell, you could use one of:

lastline=`sed -e \\\$$'{w/dev/stdout\n;d}' -i~ file`
echo $lastline 
Line #28

lastline=$(sed -e \$$'{w/dev/stdout\n;d}' -i~ file)
echo $lastline 
Line # 6

read lastline < <(sed -e \$$'{w/dev/stdout\n;d}' -i~ file)
echo $lastline 
Line # 5

Added for new year 2018

Happy new year!

Sample, simple bash functions:

fpop() { local v n=$'\n';read -r v < <(
    sed -e $'${w/dev/stdout\n;d}' -i~ "$1")
    printf ${2+-v} $2 "%s${n[${2+2}]}" "$v"
}
fshift() { local v n=$'\n';read -r v < <(
    sed -e $'1{w/dev/stdout\n;d}' -i~ "$1")
    printf ${2+-v} $2 "%s${n[${2+2}]}" "$v"
}
fsplice() {
    [ "$2" ] || return ; local v n=$'\n';read -r v < <(
    sed -e $2$'{w/dev/stdout\n;d}' -i~ "$1");
    printf ${3+-v} $3 "%s${n[${3+3}]}" "$v"
}
fpush() { sed -e "\$a$2" -i~ "$1"; }
funshift() { sed -e "1i$2" -i~ "$1"; }

Nota: Line printf ${2+-v} $2 "%s${n[${2+2}]}" "$v" is a kind of trick I use often in my functions. This line will populate a variable, if submited as second argument. If else this line will add a newline and print to STDOUT.

Little run sample:

printf "Line #%2d\n" {3..12} >file   

fpop file
Line #12
fpop file myvar
echo $myvar
Line #11

fshift file
Line # 3
fshift file myvar
echo $myvar
Line # 4

fsplice file 3 
Line # 7
fsplice file 3 myvar
echo $myvar
Line # 8

funshift file "Line # 192"
fpush file "Line # 42"

cat file
Line # 192
Line # 5
Line # 6
Line # 9
Line #10
Line # 42

declare -p myvar
declare -- myvar="Line # 8"

(The variable myvar didn't contain newline.)

And ( I can't resist! ;-):

fpop file myvar
echo $((9? ${myvar#*#} :-b))
42
like image 185
F. Hauri Avatar answered Sep 21 '22 23:09

F. Hauri