10

I am attempting to use sed to delete a line, read from user input, from a file whose name is stored in a variable. Right now all sed does is print the line and nothing else.

This is a code snippet of the command I am using:

FILE="/home/devosion/scripts/files/todo.db"
read DELETELINE
sed -e "$DELETELINE"'d' "$FILE"

Is there something I am missing here?

Edit: Switching out the -e option with -i fixed my woes!

fedorqui
  • 275,237
  • 103
  • 548
  • 598
barefly
  • 358
  • 2
  • 4
  • 13
  • Unless delete line is a line number it needs to be delimited. Please show the line in question and what the variable contain. – 123 Feb 02 '16 at 15:38
  • @123 I am uncertain, but im pretty sure bash's read takes user input as a string. I thought this might be a hurdle. How would I fix it to make it work? EDIT: Updated with variables. – barefly Feb 02 '16 at 15:40
  • 1
    Please show the line in question and what the variables contain. – 123 Feb 02 '16 at 15:41
  • Whoa [bobby tables](http://bobby-tables.com/), you need need to validate your user input: if I enter `1,$`, I've just deleted every line. – glenn jackman Feb 02 '16 at 17:29
  • @glenn jackman That it will. I have a conditional that makes sure the input is a number and within a range. The script is still in it's infancy, but since it's just for my own use I'm not too worried. – barefly Feb 02 '16 at 17:35
  • I would argue that, even for personal scripts, coding with security in mind is an essential mindset for a programmer. Maintain high personal standards and it will become a habit for all your code. – glenn jackman Feb 02 '16 at 17:37
  • @glenn jackman I'll keep that in mind as I continue to expand the script. For now I'm just trying to get all the primary uses for it up and running. – barefly Feb 02 '16 at 17:41
  • I just ran your 1,$ through my script and my conditional spit it out as it should, but unfortunately 1,2 was accepted and deleted my test entries. – barefly Feb 02 '16 at 17:48

4 Answers4

5

You need to delimit the search.

#!/bin/bash

read -r Line

sed "/$Line/d" file

Will delete any line containing the typed input.

Bear in mind that sed matches on regex though and any special characters will be seen as such.
For example searching for 1* will actually delete lines containing any number of 1's not an actual 1 and a star.

Also bear in mind that when the variable expands, it cannot contain the delimiters or the command will break or have unexpexted results.

For example if "$Line" contained "/hello" then the sed command will fail with sed: -e expression #1, char 4: extra characters after command.

You can either escape the / in this case or use different delimiters.

Personally i would use awk for this

awk -vLine="$Line" '!index($0,Line)' file

Which searches for an exact string and has none of the drawbacks of the sed command.

123
  • 10,778
  • 2
  • 22
  • 45
  • Technically your command didn't work, but thats only because it needed the -i option. In fact my command works without the delimiter now using only the -i option. So essentially sed -i "$LINE"'d' "$FILE" works just fine. Thanks for your help! – barefly Feb 02 '16 at 16:48
  • 2
    With bash, you can walk through the leaning-toothpick forest: `sed "/${Line//\//\\/}/d" file` to escape any slashes in the parameter. But +1 for suggesting a string comparison function instead of regular expressions. – glenn jackman Feb 02 '16 at 17:33
  • If you are concerned that there might be `/` characters in the variable, you can always change the delimiter sed uses, in this case using `:` as delimiter: ```sed "\:$Line:d"``` – AlexR Mar 06 '19 at 13:28
  • @AlexR Yep, mentioned that `You can either escape the / in this case or use different delimiters.` – 123 Mar 06 '19 at 14:03
2

You might have success with grep instead of sed

read -p "Enter a regex to remove lines: " filter
grep -v "$filter" "$file"

Storing in-place is a little more work:

tmp=$(mktemp)
grep -v "$filter" "$file" > "$tmp" && mv "$tmp" "$file"

or, with sponge (apt install moreutils)

grep -v "$filter" "$file" | sponge "$file"

Note: try to get out of the habit of using ALLCAPSVARS: one day you'll accidentally use PATH=... and then wonder why your script is broken.

glenn jackman
  • 238,783
  • 38
  • 220
  • 352
1

Please try this :

sed -i "${DELETELINE}d" $FILE
Amirhossein Yari
  • 2,054
  • 3
  • 26
  • 38
Shahin
  • 19
  • 2
1

I found this, it allows for a range deletion with variables:

#!/bin/bash

lastline=$(whatever you need to do to find the last line)` //or any variation

lines="1,$lastline"

sed -i "$lines"'d' yourfile

keeps it all one util.
codedge
  • 4,754
  • 2
  • 22
  • 38
Bryan
  • 11
  • 1