CLI: batch file rename -- with CONTENT ?? (e.g. specific text mentioned in file)

2

I would like to batch rename files (*.txt) by inserting a number of the format 'RXR1234567' (RXR+7digits) [if such number (and ideally only one) is found in the text] at the front of the filename, e.g. instead of

letter_235.txt

the file should be called

RXR1234567_letter_235.txt

Could this be done from the command line (grep, rename)? The files are in various subdirectories.

Your thoughts will be appreciated (as always).

ajo

Posted 2010-10-02T21:00:17.097

Reputation: 785

Answers

1

Try this in the root directory:

find -name '*.txt' -exec sh -c 'PREFIX=`grep -m 1 -oe "RXR[0-9]\{7\}" "$0"` && mv "$0" "${0%/*}/${PREFIX}_${0##*/}"' {} \;

Note: If a file contains multiple matches of the pattern the first one will be used.

cYrus

Posted 2010-10-02T21:00:17.097

Reputation: 18 102

I'm a bit apprehensive to do the mv right away... I've done PATTERN='RXR[0-9]{7}' but would like to first see what happens:

grep $PATTERN *.txt

is OK, but:

grep $PATTERN *.txt -exec sh -c 'grep $PATTERN "$0$"' {} ;

just produces lines like '<filename>:0' – ajo – 2010-10-02T21:52:12.287

... typo above: I DID do "$0" and not "$0$" – ajo – 2010-10-02T21:58:15.883

I thought that PATTERN was known before as plain text and not as regex. I've edited the answer, now it should do what you want (see the note). Anyway you can test the effects of that command by substituting mv ... with echo mv .. and removing > /dev/null. If something is unclear just ask! – cYrus – 2010-10-03T00:51:21.377

find -name '.txt' -exec sh -c 'PREFIX=grep -m 1 -oe "RXR[0-9]\{7\}" "$0" && echo ${PREFIX}' {} ; - this makes me see all the RXR results (I'm impressed!); I'll try the rest in a minute – ajo – 2010-10-03T02:45:33.883

unfortunately, the second part doesn't seem to work?! (the files seem unchanged). What does ${0%/} mean (?directory), and ${0##/} (?filename)? - Actually, the subdirectories are not essential, if I could get it working in a single directory that would already be great... – ajo – 2010-10-03T02:51:32.220

No, actually it did work (for a number of files, but due to them starting with RXR... they were all in the middle of the list....). [I did the command twice now, those files have now ended up with RXR1234567_RXR1234567_letter125.txt, but I hope I can get that sorted with rename...) I'd still be interested in the meaning of "{0%/}" and "${0##/}", if you've got some time to explain that... And of course the fact that you've done the job with the command line, is simply amazing - Thank you for your help. – ajo – 2010-10-03T03:05:29.513

@ajo: {0%/*} does the same thing as dirname (outputs the directory without the filename) and ${0##*/} does the same thing as basename (outputs the filename without the directory). – Paused until further notice. – 2010-10-03T07:04:36.693

@Dennis Williamson: Thank you Dennis that way is more readable. – cYrus – 2010-10-03T11:24:01.167

@ajo: Dennis already show you the meaning of them. If you want more info take a look at man bash, section Parameter Expansion. – cYrus – 2010-10-03T11:28:46.490

how would I write the argument for 'dirname' in the above?? – ajo – 2010-10-05T06:11:46.130

Does this look okay? find -name '*.txt' -exec sh -c 'PREFIX=$(grep -m 1 -oe "[Rr][Xx][Rr][0-9]{7}" "$0") && mv "$0" "$(dirname {})/$(basename {})"' ; – ajo – 2010-10-05T07:19:45.380

Not exactly: find -name '*.txt' -exec sh -c 'PREFIX=$(grep -m 1 -oe "[Rr][Xx][Rr][0-9]{7}" "$0") && mv "$0" "$(dirname $0)/${PREFIX}_$(basename $0)"' {} ; You missed the PREFIX and the last {} that passes the file argument to sh. Also I would use $0 rather {} inside the sh command. – cYrus – 2010-10-05T13:07:36.803