0

Previous topic - https://stackoverflow.com/questions/40808975/overwrite-script-in-bash-shell

I'm working on a university project where we have to create a recycling bin with a del and restore option. I have completed both of these parts and the restore option works (mostly). It saved the location of the deleted file in a txt file called FilePaths to be used as reference when restoring the file back to it's original location.

I know that when duplicates of a file location are saved into this file it causes problems so I have to create a line in a bash script that deletes the specific file location string from the text file.

I know sed can help and I can manipulate it to do whatever i want it to however the problem is it doesn't seem to do anything at all. I've even tested it using a simple "test2" text file with the word hello inside.

sed '/hello/d' test2

this does absolutely nothing. I've tried it with double quotes and still absolutely nothing, it doesn't remove "hello" from my test2 file at all

In terms of the restore function, this is what I have so far

#!/bin/sh
#navigate to the Recycle_Bin directory
cd $HOME/Recycle_Bin

#take the string from FilePaths and save it to restore
restore="$(grep "$1" "$HOME/FilePaths")"

#take the string saved in restore and use it as the file's path
filename="$(basename "$restore")"

#remove the string matching restore within FilePaths
sed '/$restore/d' $Home/FilePaths

#set location
location="$(readlink -f "$location")"

#move file to original location
mv -i "$1" "$(grep "$1" "$HOME/FilePaths")"

Can anyone think of any reason why sed won't work? I've been searching for hours and can't find any answer, I could use awk but I feel sed would make my code simpler

Community
  • 1
  • 1
Mark Barton
  • 847
  • 6
  • 15
  • Have you really checked the output of `sed '/hello/d' test2` ? did it still contain lines with `hello` (the output, not the file)? If it did, can you try `echo "hello" | sed '/hello/d'` ? It should supposedly output nothing. – Aaron Nov 29 '16 at 20:30
  • An easy fix at least, as commented on JNevill's answer, is that you should use double-quotes around your `sed` command that reference the `$restore` variable, or it won't get expanded. – Aaron Nov 29 '16 at 20:31
  • so would I put it as `sed -i "/"$restore"/d" $HOME/FilePaths` – Mark Barton Nov 29 '16 at 20:33
  • There's too many quotes here, just `sed -i "/$restore/d" $HOME/FilePaths`. Double and single quotes share some effects (they mark their content as a single field) but double quotes ask the shell to inspect the string and expand its content when appropriate, while the single quotes contain just text from the shell perspective – Aaron Nov 29 '16 at 20:34
  • I'm now getting an error `sed: -e expression #1, char 0: no previous regular expressions` – Mark Barton Nov 29 '16 at 20:38
  • Hmmm your `$restore` must contain `/`, which will break the `/.../` sed syntax. To debug this yourself, just add an echo in front of your `sed` command and see if it prints a valid `sed` command. – Aaron Nov 29 '16 at 20:41
  • 1
    When you confirm that you don't have a nice `/.../` command anymore, there are two options available to you : either escape every `/` of your `$restore` variable before passing it to `sed`, or use another separator in `sed` that you're sure won't be found in your `$restore` variable (altough `/.../` is the norm, any separator can be used : I regularly use `+...+` or `%...%` when I'm dealing with a lot of `/`) – Aaron Nov 29 '16 at 20:43
  • oh yes it does. Right now it stored the location of a deleted file called /root/test – Mark Barton Nov 29 '16 at 20:44
  • total noob question but could you show me an example of adding those separators? – Mark Barton Nov 29 '16 at 20:57
  • `sed 's/searchFor/replaceBy/'` is the same thing as `sed 's+searchFor+replaceBy+`. Same for `sed '/test/d'` and `sed '+test+d'`. Note that `sed 's/I want to replace a >/by /` wouldn't work because the first `/`, which should be part of the searched pattern, is understood as the end of the searched pattern. However, `sed 's+I want to replace a >+by +` will work, since we use `+` as a separator rather than `/`. There were some typos in my previous comment, I've rewritten it – Aaron Nov 29 '16 at 21:08
  • it's fixed the problem however /root/test still isn't getting removed from the FilePaths file. – Mark Barton Nov 29 '16 at 21:12
  • It's good, it means your `sed` command works ;) Now you're `grep`ing from a file which does not contain the reference to your recycled file anymore. Just `grep` and `mv` before your `sed` :) – Aaron Nov 29 '16 at 21:17
  • Ah perfect! thank you very much Aaron, I really appreciate your help on this issue. I'll add a final answer – Mark Barton Nov 29 '16 at 21:20
  • You're welcome! Have fun with `bash` and GNU Tools. It's hard to learn because there's a different tool for everything and so much to know, but it's efficient when you know it for the exact same reasons :) – Aaron Nov 29 '16 at 21:24
  • You could use `sed -i "/${restore//\//\\/}/d" $Home/FilePaths`. – alvits Nov 30 '16 at 00:44

3 Answers3

1

Your sed command isn't writing the results anywhere so it's defaulting to stdout. You should use the -i flag to edit the file in place.

sed -i "/$restore/d" $Home/FilePaths

If that is still giving you problems you could use:

sed -i "s/$restore//g" $Home/FilePaths

Which, if $restore is the entire content of the line in the file, will do the same thing.

JNevill
  • 46,980
  • 4
  • 38
  • 63
  • It's my understanding that `//d` will remove the entire line that contains the `` (I may be wrong about that as I usually just `s///g`. That's a different behavior that `s///g` which felt like OP's intent. The behavior of the two is different, but if `` is the only thing found on the line, then the two commands will have the same results. – JNevill Nov 29 '16 at 21:08
  • That's right, my last comment was wrong. I've upvoted both your answer and the other one as both have a part of the solution to OP's problem : use `-i` to modify the file in place, use double quotes to get the text expanded, and take care that it doesn't produce any unwanted `sed` separator/marker. – Aaron Nov 29 '16 at 21:19
  • Note that this will run into trouble if `$restore` contains any slashes for the file name it is restoring. – Jonathan Leffler Nov 29 '16 at 21:22
1

As your path could contain /, you may have to use another marker:

Try one of

sed -e "\|$restore|d" -i $Home/FilePaths

or

sed -e "\@$restore@d" -i $Home/FilePaths

(Thanks to Jonathan Leffler for his comment).

Community
  • 1
  • 1
F. Hauri - Give Up GitHub
  • 64,122
  • 17
  • 116
  • 137
  • 1
    Yes, you have to use another marker; that isn't the POSIX way to choose the marker. Does it work in GNU `sed`? POSIX requires `"\|$restore|d"` where the backslash indicates that this is a search with the next character as a delimiter. – Jonathan Leffler Nov 29 '16 at 21:22
  • Thanks @JonathanLeffler I've tested with `s|||` command, but not as an *address*... -No, this won't work without backslashes `\\` under *GNU sed*. – F. Hauri - Give Up GitHub Nov 29 '16 at 21:55
0

Thank you to everyone for your help especially to both Aaron and JNevill who were a great help in answering this question.

I was able to get this working using this code

sed -i "s+$restore++g" $Home/FilePaths

as well as using + delimiter it is possible to use other symbols most notably the @ incase the + symbol is used within a string's file path.

I also moved this line from above the location property and down to the very bottom. This meant that it was deleted after the location had been used in the location property

My full code

#!/bin/sh
#navigate to the Recycle_Bin directory
cd $HOME/Recycle_Bin

#take the string from FilePaths and save it to restore
restore="$(grep "$1" "$HOME/FilePaths")"

#take the string saved in restore and use it as the file's path
filename="$(basename "$restore")"

#set location
location="$(readlink -f "$location")"

#move file to original location
mv -i "$1" "$(grep "$1" "$HOME/FilePaths")"

#remove the string matching restore within FilePaths
sed -i "s+$restore++g" $Home/FilePaths

Hope this helps

Mark Barton
  • 847
  • 6
  • 15
  • 1
    Thanks for adding an answer. To mark this as solved, would you click on the tick mark adjacent to the most helpful solution? You may accept your own if you wish, though it is usually a kindness to award it to someone else. – halfer Nov 29 '16 at 22:10
  • One problem you will ultimately face is that any character you pick as your sed expression delimiter, such as the `+` here in your example, is legal as a character in a file or directory name. What happens if I delete the file `/var/tmp/this+that.txt` or `/var/tmp/dir+name/file.txt`? – Stephen P Nov 29 '16 at 23:03
  • in that case I will add a section explaining this delimiter choice – Mark Barton Nov 30 '16 at 16:38