0

I understand this question has been asked a lot in the bash / perl world.

I can appreciate the answer here Interactive search and replace from shell

:argdo %s#SEARCH#REPLACE#gec |update

This works okay for me, and I do like and use vi.

But I want to take this concept to the next level

the answer given at the above link is as follows: sed -i -e 's/foo/bar/g' filename again this works.

so in the interest of making this an executable / interactive script.. I tried something like this:

#!/bin/sh

read -r -p "Search For: " FIND 
read -r -p "Replace With: " REPLACE 
read -r -p "Full Path To File: " FILE 

sed -i -e 's/"${FIND}"/"${REPLACE}"/g' "$FILE" 

however, if you are reading this, you probably know that you can't run sed like this inside a bash script.

Any thoughts on making this find_replace.sh a working script?

Thanks for reading.

Community
  • 1
  • 1
RobBenz
  • 589
  • 1
  • 7
  • 21
  • Replace the single quotes around `sed`'s script, to double-quotes i.e. `"s/$find/$replace/g"`. Single quotes (') cause everything between them to be taken literally by bash, thus `"$replace"` and `"$find"` are not being expanded. – Rany Albeg Wein Feb 01 '16 at 21:18
  • You should also sanitize your input. Even if you fix the quotes, if someone were to add a slash and other parameters to one of the input variables, they could execute arbitrary sed commands on your system. Your question is tagged [tag:bash], but you're running this script in POSIX mode because of the shebang. Fix your shebang, then `FIND="${FIND////}"` after you `read`. – ghoti Feb 01 '16 at 21:22
  • okay, maybe I'm a little outside my comfort realm, this is great input. to the best of my knowledge this was a `bash` question, so for that i apologize. – RobBenz Feb 01 '16 at 21:25
  • @ghoti what would be the proper shebang for this script? -`#!/usr/bin/env bash` ? – RobBenz Feb 01 '16 at 21:37
  • Perfect. :) That keeps things portable in case you need to run this in a machine with bash somewhere other than /bin It's a good habit to be in. – ghoti Feb 01 '16 at 21:46

1 Answers1

1

First of all, you should switch the single quotes and double quotes on your last line. In that way bash will replace your variables with the values. Second of all, you should add some escaping around the FIND and REPLACE values. For the case where in one would use values containing / characters.

  • Thank you! I am looking into the character escaping now. – RobBenz Feb 01 '16 at 21:27
  • That one is really tuff. I was looking into this: FIND=$(echo "$FIND" | sed 's|/|\\\/|') REPLACE=$(echo "$REPLACE" | sed 's|/|\\\/|') but it doesn;t really help, since now, one can not use a | character anymore. You culd of coarse try to find a character that is not used in the input and use that in the first sed I wrote. But I think it is best to choose e.a. python instead of bash. It has a better distinction between language and data. – Sebastiaan Mannem Feb 01 '16 at 21:32
  • Thanks! If I understand correctly those variables would be defined after the user-prompts, and before the final sed execution? – RobBenz Feb 01 '16 at 21:34
  • Yes, they should be there before the last line containing sed. – Sebastiaan Mannem Feb 01 '16 at 21:35
  • WHat do you mean with recursive? – Sebastiaan Mannem Feb 01 '16 at 21:43
  • well, if for example, I wanted to run this script for every file within a directory, and any file within subdirectories of initial directory. – RobBenz Feb 01 '16 at 21:44
  • To escape those characters sed might find "special", see http://stackoverflow.com/a/24914337/1745001. Alterantively - use awk instead of sed since awk can process literal strings, unlike sed which can only work on regexps with additional restrictions. – Ed Morton Feb 01 '16 at 21:47
  • you could do something like: find $PATH -name "*${NAME}*" | while read FILE; do sed ..... ; done – Sebastiaan Mannem Feb 01 '16 at 21:47
  • Thanks for the great input everyone – RobBenz Feb 01 '16 at 21:50