LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   Find/Replace shell script that replaces word with other word in text, filenames (https://www.linuxquestions.org/questions/programming-9/find-replace-shell-script-that-replaces-word-with-other-word-in-text-filenames-4175426625/)

yanom 09-10-2012 09:35 PM

Find/Replace shell script that replaces word with other word in text, filenames
 
I'm trying to write a shell script that will

1) be activated with command-line arguements (
Code:

./renamescript wordone wordtwo
)
2) recursively traverse through all the non-binary files in all the directories inside the directory where the shell script lives, replacing all instaces of the first string with the second string
3) do the above, except replace all instances of the first string with the second string in filenames (e.g. blahwordoneblah.lua would become blahwordtwoblah.lua

I don't have much in the way of shell scripting skills, so this seems impossible to me. Does anyone know how this could be done?

konsolebox 09-11-2012 12:41 AM

Using a script:
Code:

#!/bin/bash

PATTERN=$1
REPLACEMENT=$2

IFS=$'\t'

while read DIR FILE; do
        echo mv "$DIR/$FILE" "$DIR/${FILE//$PATTERN/$REPLACEMENT}"
done < <(exec find -type f -printf "%h\t%f\n")

Code:

# bash script.sh abc xyz
Please see find's manual to see more options about selecting the file types.

P.S. At least tell, this is not your homework right? Well I don't really mind :)

everest40 09-11-2012 01:34 AM

I think this will do what you want, except it does not exclude binaries:

Code:

#!/bin/bash

for infile in `find -depth -readable -writable -type f`
do
        outfile=`echo $infile | sed "s/$1/$2/"`
        sed "s/$1/$2/" $infile > temporary
        rm $infile
        mv temporary $outfile
done


David the H. 09-11-2012 02:50 AM

1) This sounds a bit like homework. I hope you aren't trying to make us do your work for you.

2) Renaming files and processing text in them are subjects that come up repeatedly. A quick LQ search will turn up dozens of them. It should then be a simple matter to extrapolate the techniques into a single script.


Code:

for infile in `find -depth -readable -writable -type f`
do
        outfile=`echo $infile | sed "s/$1/$2/"`
        sed "s/$1/$2/" $infile > temporary
        rm $infile
        mv temporary $outfile
done

Sorry, but this is incorrect. Don't Read Lines With For. To safely use the output of find, use a while+read loop and set find to output null-terminators between the filenames.

How can I read a file (data stream, variable) line-by-line (and/or field-by-field)?
http://mywiki.wooledge.org/BashFAQ/001

Also, $(..) is highly recommended over `..`. But actually, process substitution works better in a while loop.

Finally, parameter substitution can be used instead of sed.

Code:

while IFS='' read -r -d "" infile; do

        outfile=${infile//$1/$2}
        sed "s/$1/$2/g" "$infile" > "$outfile"
        rm "$infile"

done < <( find -depth -readable -writable -type f -print0 )


everest40 09-11-2012 04:14 AM

Thanks for the scripting tips, David :)

yanom 09-11-2012 09:36 AM

thanks, I will try these out. And no, this is not homework, despite the highly specific requests. I'm developing a game in Spring engine and wanted the ability to rename a unit. This unfortunately means going through directories of game code and objects, replacing one name with another. I needed a shell script to do this quickly.

konsolebox 09-11-2012 10:02 AM

@yanom: And what do you actually mean about "non-binary" files? Is it just anything that's ASCII? I think using the utility command "file" would help. You could use the output of it to compare with pattern(s) in case..esac or [[ =[=/~] ]].

yanom 09-11-2012 07:43 PM

Quote:

Originally Posted by konsolebox (Post 4777757)
@yanom: And what do you actually mean about "non-binary" files? Is it just anything that's ASCII? I think using the utility command "file" would help. You could use the output of it to compare with pattern(s) in case..esac or [[ =[=/~] ]].

a couple of the files are 3D models and I don't want the program messing with those and possibly corrupting them.

also, this line of code does the neccessary work of replacing the filenames:
Code:

for infile in `find . \( ! -regex '.*/\..*' \)`
do
        newname=`echo $infile | sed "s/$1/$2/"`
        if [ "$infile" != "$newname" ]
        then
                git mv $infile $newname
        fi
done

now it's just necessary to edit the text in-file

konsolebox 09-12-2012 12:29 AM

Ok.
Quote:

Originally Posted by yanom (Post 4778057)
now it's just necessary to edit the text in-file

Sorry I didn't get that clearly. Specifically what would you edit, and where or how?


All times are GMT -5. The time now is 06:23 AM.