Join 3,520 readers in helping fund MetaFilter (Hide)

Tags:

Rename my files
December 29, 2012 1:27 PM   Subscribe

Is there a Unix command (Mac OS X Terminal) or a command-line program that will rename a series of plain-text files based on the first line of each?
posted by megatherium to Computers & Internet (13 answers total) 1 user marked this as a favorite
 
Not that I can think of, but if you can describe what you want someone can probably whip up a shell recipe for you.
posted by jjwiseman at 1:27 PM on December 29, 2012


Sure, an awk command piped into /bin/sh would do the trick, where the awk command reads the first line of the file and then prints the desired mv command to /bin/sh. Feel free to post specifics and I'm sure one of us can help you with a quick one-liner.
posted by Blazecock Pileon at 1:37 PM on December 29, 2012


I can write this script for you. Is the first line in the file the exact name you want?

Posting an example might be helpful.
posted by ryanrs at 1:42 PM on December 29, 2012


You can easily do this with head -n1 and mv.
posted by Precision at 1:42 PM on December 29, 2012


for x in *; do echo mv "$x" "$(head -n 1 "$x")"; done

This will rename all the files in the current directory. You REALLY REALLY need to back up the files before you try it. Also if any of the new filenames have special characters (especially "/"), things will go terribly wrong.
posted by ryanrs at 1:46 PM on December 29, 2012 [4 favorites]


you might want to 'cp' instead of move, come to think of it.
posted by empath at 2:08 PM on December 29, 2012


He did say "based" on the first line so I expect there will be some transform, perhaps a sed string that the first line is piped into. Off the cuff, untried:

for x in *; do echo mv "$x" "$(head -n 1 "$x|sed /foo\s/bar_/")"; done


If there are many files you really really want to make a test directory of 2-3 files for testing until you're sure the pattern is right.
posted by sammyo at 2:37 PM on December 29, 2012


I would actually back up the whole directory before doing something like ryanrs's otherwise excellent answer. Using mv -i will let you approve each move one by one.
posted by grouse at 3:05 PM on December 29, 2012


In Linux you could do
grep --line-number --with-filename --recursive "«first line regex»" «/source/directory/»* | grep --only-matching "^[^:]*:1:" - | sed s/:1://g | xargs --interactive -i mv {} {}«.newextension»
so that for example
grep --line-number --with-filename --recursive "^#\!/bin/" /home/username/* | grep --only-matching "^[^:]*:1:" - | sed s/:1://g | xargs --interactive -i mv {} {}.sh
would recursively rename all shell scripts (or at least all files beginning with "#!/bin/" on the first line) to «filename».sh in /home/username.

xargs will prompt you before each rename (remove the "--interactive" option to do it all automatically) but it's still not a bad idea to back everything up before you do this.
posted by XMLicious at 3:21 PM on December 29, 2012


Note: you may find suggestions from Linux users don't work on Mac OS because Apple ships absurdly old and buggy versions of basic shell utilities.
posted by ryanrs at 3:33 PM on December 29, 2012 [3 favorites]


An example file is named b17.txt and its first several lines are:

550.1206 Funds, property, and business of health care corporation; investments; insurance; prepaid health care benefits.
Sec. 206.

(1) The funds and property of a health care corporation shall be acquired, held, and disposed of only for the lawful purposes of the corporation and for the benefit of the subscribers of the corporation as a whole. A health care corporation shall only transact business, receive, collect, and disburse money, and acquire, hold, protect, and convey property,

I want it to be renamed
550.1206 Funds, property, and business of health care corporation; investments; insurance; prepaid health care benefits.txt

or

550.1206 Funds, property, and business of health care corporation.txt

IOW, the first 50 or so characters would suffice.

The existence of periods and commas is a complication.

I tried ryan's and sam's suggestions but they did not work.

I am working with a copy directory so my original source files are safe.

Thank you.
posted by megatherium at 3:55 AM on December 30, 2012


Ryan's has an echo before the mv, so it doesn't actually do the mv. As your file names have spaces in them, I suggest setting IFS="" before the loop.

IFS=""; for x in *; do mv -i "$x" "$(head -n 1 "$x")"; done

The -i for mv is to stop you from clobbering files in case you have two that wind up with the same name.
posted by fings at 8:55 AM on December 30, 2012 [1 favorite]


Thank you, fings. That one works.
posted by megatherium at 5:37 PM on December 30, 2012


« Older I am having serious psychologi...   |  I've been spending time in a h... Newer »
This thread is closed to new comments.