1

I need to search through many files in a directory for a list of keywords and add a prefix to all of them. For example, if various files in my directory contained the terms foo, bar, and baz, I would need to change all instances of these terms to: prefix_foo, prefix_bar, and prefix_baz.

I'd like to write a shell script to do this so I can avoid doing the search one keyword at a time in SublimeText (there are a lot of them). Unfortunately, my shell-fu is not that strong.

So far, following this advice, I have created a file called "replace.sed" with all of the terms formatted like this:

s/foo/prefix_foo/g
s/bar/prefix_bar/g
s/baz/prefix_baz/g

The terminal command it suggests to use with this list is:

sed -f replace.sed < old.txt > new.txt

I was able to adapt this to replace instances within the file (instead of creating a new file) by setting up the following script, which I called inline.sh:

#!/bin/sh -e
in=${1?No input file specified}
mv $in ${bak=.$in.bak}
shift
"$@" < $bak > $in

Putting it all together, I ended up with this command:

~/inline.sh old.txt sed -f replace.sed

I tried this and it works, for one file at a time. How would I adapt this to search and replace through all of the files in my entire directory?

1
  • Run your script through shellcheck.net and fix the issues it flags -- my answer is safe against filenames with spaces and such on its own, but your inline.sh currently is not safe in that same respect. Commented Mar 7, 2015 at 0:18

2 Answers 2

2
for f in *; do
  [[ -f "$f" ]] && ~/inline.sh "$f" sed -f ~/replace.sed
done
Sign up to request clarification or add additional context in comments.

3 Comments

Now, how would I make this recursive?
@unifactor, what version of bash? If 4.0 or newer, shopt -s globstar and then use for f in **/*.
...if older than that, then find . -type f -exec ~/inline.sh '{}' sed -f ~/replace.sed ';'
1

In a script:

#!/bin/bash
files=`ls -1 your_directory | egrep keyword`

for i in ${files[@]}; do
    cp ${i} prefix_${i}
done

This will, of course, leave the originals where they are.

2 Comments

...also, you're using array syntax at expansion time (incorrectly, given lack of quotes), but you aren't actually defining files as an array (which is why adding quotes without fixing the way files is defined to actually be an array will break things).
files=( your_directory/*keyword* ) would be the array-assignment equivalent, btw, thereafter for i in "${files[@]}"; do cp "$i" "prefix_$i"; done. The curly braces in ${i} don't have any impact on correctness here -- one can take them or leave them in this particular use case -- but the lack of quotes is actually harmful for filenames that can also be intepreted as glob expressions or which contain characters in IFS.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.