63

Lets say I have a directory full of .md files all named various things. Lets say I wanted to prepend "test" to the front of each file name. So for example: file a.md, b.md, and c.md would become test - a.md, test - b.md, and test - c.md.

How would I accomplish this via command line?

ZygD
  • 2,459
  • 12
  • 26
  • 43
Jesse Atkinson
  • 917
  • 3
  • 10
  • 11

7 Answers7

87

One-liner that can be easily typed straight from the terminal:

for f in *.md; do mv "$f" "test - $f"; done

Or rewritten on separate lines instead using semicolons:

for f in *.md
do
    mv "$f" "test - $f"
done

Exposition

Syntax of for (in sh):

for NAME [in WORDS ... ] ; do COMMANDS; done

Here, our NAME is f and our WORDS are all files in the current directory matching *.md. So the variable $f will be be substituted with each file matching *.md.

So for a.md:

mv "$f" "test - $f"

becomes

mv "a.md" "test - a.md"

The quotes are important because the each filename $f might contain spaces. Otherwise mv would think each word was a separate file. For example, if there were no quotes, and there's a file called Foo Bar.md, it would translate as:

mv Foo Bar.md test - Foo Bar.md

which would not work as intented. But by wrapping $f in quotes, it makes sense:

mv "Foo Bar.md" "test - Foo Bar.md"

Noting the syntax of for, you could also rename a subset of all the *.md files by naming each explicitly:

for f in a.md b.md d.md; do mv "$f" "Test - $f"; done

Or using shell expansion:

for f in {a,b,d}.md; do mv "$f" "Test - $f"; done
Daniel Hanrahan
  • 1,228
  • 1
  • 9
  • 10
  • This is exactly what I needed to see. Thanks! – Ryan May 19 '16 at 16:10
  • Great, served well for renaming all files to have .yaml extension, for f in ./*; do mv "$f" "$f.yaml"; done – anVzdGFub3RoZXJodW1hbg Jul 31 '20 at 12:40
  • Great, thanks! For appending to the end of a filename but before the file extension, I did: `filename="${f%.*}"; mv "$filename.md" "$filename textToAppend.md"` inside the loop. I made use of this answer: https://stackoverflow.com/q/965053/17616747 – David Dec 27 '22 at 00:14
11

If you have prename...

prename 's/^/test - /' *.md

Using ordinary shell commands:

for file in *.md; do
    mv "$file" "test - $file"
done
u1686_grawity
  • 426,297
  • 64
  • 894
  • 966
7

mmv1,2 is also a very nice tool for such a task, applied to the current job, it would be

mmv '*.md' 'test - #1.md'

Of course, if you only want to add "test - " to a.md, b.md and c.md, but not a1.md, something like

mmv '?.md' 'test - #1.md'

would be more appropriate.

I can really suggest it, especially if you have many such problems.

If you are additionally looking for a graphical interface, try gprename.

Claudius
  • 8,808
  • 1
  • 15
  • 13
6

Instead of using a for loop, which will fail on spaces unless you redefine the IFS variable, I would recommend using a while loop combined with find. The following will work when run from the same directory as the files

find . -maxdepth 1 -type f -name '*.md' | while read -r file; do
    file=$(basename $file)
    mv "$file" "test - $file"
done

the "basename" line is in there so that find will print the file name only - without path components which would make the rename operation break.

  • This is exactly what I am looking for. I want to implement in Automator a way to prepend text to file names. How to modify this code to just apply the preprend operation on $@? (without any specific extension)? Thanks! for f in *.md do mv "$f" "test - $f" done – Emmanuel Goldstein Dec 11 '20 at 07:19
  • Have a look at this: https://mywiki.wooledge.org/BashPitfalls#for_arg_in_.24.2A – Friedrich 'Fred' Clausen Dec 13 '20 at 10:55
3

I know it's really late, but if anyone else is looking for something like this, then this worked for me:

rename '' 'name -' *.md
nullptr
  • 131
  • 4
0

In bash, adding "Prepend text - " to all files in folder:

for i in *; do mv "$i" "$(echo $i | sed 's/^/Prepend\ text\ \-\ /')"; done;
Tim Chaubet
  • 111
  • 2
0

If you have zsh available you could use zmv:

autoload zmv
zmv -w '*' 'test - $1'

You can test the command with:

zmv -wn '*' 'test - $1'
  • -n means dry-run, i.e. only show what will happen.
  • -w implicitly puts parenthesis around wildcards, makes backreferences work.
Thor
  • 6,419
  • 1
  • 36
  • 42