Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I'm new with Linux, sed, and awk but I don't mind challenging myself on new ideas. That being said, I understand the purpose and how to use rename and sed for a common event such as adding a $date or removing a _1234 from all the files. However, I want to figure out how to rename 100's of files that have no relation to one another other than the file type.

Renaming example:

  • old name alpha.ai renamed to omega.ai
  • old name pie32.ai renamed to apple.ai
  • old name xmas.ai renamed to santa.ai

I originally used a bash script to pull all the names to a .csv file and placed them in column A. In column B I wrote in the new names. Now since there is not a common event occurring how could you write sed or the like to do this??

for i in *.ai
        mv $i $(echo $i | sed "a1,b1")

share|improve this question
It is tricky to rename all special characters by automated scripts, you can find a link to my script in this answer: superuser.com/a/858671/365691 – A.Danischewski Dec 30 '14 at 23:42
up vote 5 down vote accepted

If you happen to have a file that looks like this:

old_name1, new_name1
old_name2, new_name2
old_name3, new_name3

You can do a dirty little trick:

sed 's/^/mv -vi "/;s/, /" "/;s/$/";/' < names.csv | bash -

The sed comamnds (delimited by semicolons) does this (s is for substitute, / is used as a delimiter, any other character would do, @ is often used as well):

  • s/^/mv -vi "/ - adds mv -vi " at the beginning of each line (^ is beginning of line);
  • s/, /" "/ - replaces comma followed by a space with " ";
  • s/$/";/ - appends double quotes to all lines ($ means end of line)

and hence the output of sed will be this:

mv -vi "old_name1" "new_name1"
mv -vi "old_name2" "new_name2"
mv -vi "old_name3" "new_name3"

which will be fed to bash to execute. The quotes around filenames are not mandatory, they just guard any possible spaces in the filenames (however they will defintely not help against spaces followed by a comma, since that is used as delimiter). the -v instructs mv to display what it is doing (in case something goes wrong, you'll know what happened), -i will cause it to ask if it were to overwrite already existing file.

share|improve this answer
I get a mv: missing destination?? – Darth_Vader Dec 6 '12 at 17:19

There are several quoting problems in your script. It will mangle file names containing special characters: whitespace, \[?*-.

**Always use double quotes around variable substitutions "$i" and command substitutions "$(sed …)". Without double quotes, the value of the variable is interpreted as a list of whitespace-separated wildcard patterns, and each pattern is replaced by the list of matching file names (if there are no matches, the pattern is left alone).

Also, if a file name begins with -, it will be interpreted as an option by mv and possibly by echo. Pass -- first to tell the command that there will be no more options.

for i in *.ai; do
  mv -- "$i" "$(printf '%s\n' "$i" | sed 's,a1,b1,')"

(This still assumes that your file names don't contain newlines.) (I also fixed the sed argument into what you presumably meant.)

If your list of file names is plain comma-separated with no quotes, you can parse it with a shell script. This assumes that there are no commas or newlines in any file name.

while IFS=, read -r from to junk; do
  mv -- "$from" "$to"
done <"$files_to_rename.csv"

If your input file is a CSV file with possible quoting, use a real CSV parser. Don't try to roll your own. See Is there a robust command line tool for processing csv files? For example, in Python (with the CSV on standard input):

import csv, os, sys
for line in csv.reader(sys.stdin):
    (source, dest) = line
    os.rename(source, dest)
share|improve this answer

If your files have funny characters (',",\,$), you can loop over the file and read it into a bash array.

while IFS=, read -r -a arr; do mv "${arr[@]}"; done <files.csv 
share|improve this answer

When faced with this sort of problem I usually to the sed/bash trick by hand.

  1. I either write an editor macro or a silly little program that reads in the csv file and writes lines of the form 'mv file1 file2'.
  2. Then I run the script (or macro) and save the output to run-my-cmds.sh
  3. Inspect run-my-cmds.sh visually to make sure it will to the right things
  4. bash run-my-cmds.sh
share|improve this answer

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.