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?
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
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
Posting an example might be helpful.
posted by ryanrs 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]
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
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
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
posted by grouse at 3:05 PM on December 29, 2012
In Linux you could do
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
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 examplegrep --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]
posted by ryanrs at 3:33 PM on December 29, 2012 [3 favorites]
Response by poster: 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
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]
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]
Response by poster: Thank you, fings. That one works.
posted by megatherium at 5:37 PM on December 30, 2012
posted by megatherium at 5:37 PM on December 30, 2012
This thread is closed to new comments.
posted by jjwiseman at 1:27 PM on December 29, 2012