Shell script to rename multiple files from their p

2019-07-15 15:03发布

问题:

I have a file structure like this:

  • 00000010
    • 000000001.file1
    • 000000001.file2
  • 00000020
    • 00000003.file1
    • 00000003.file2
    • 00000003.file3
  • ...

So there are folders with 8-digit names containing one ore more files with name starting with 8-digit numbers. But theses filenames are – let's say – out of sync. So Now I try to rename them recursively in bash to archive:

  • 00000010
    • 000000010.file1
    • 000000010.file2
  • 00000020
    • 00000020.file1
    • 00000020.file2
    • 00000020.file3
  • ...

My script does look like:

#! /bin/bash

find * -maxdepth 1 -name "*" -type d | while read -r dir
do
        rename 's/$dir\/[0-9]{8}/$dir/' *
done

But this is not working and gives errors like

Global symbol "$dir" requires explicit package name at (eval 1) line 1.

How could I write it to rename the files according to their folder names?

Thank you for help!

回答1:

Use " in place of ' in rename

You should run rename on the files inside $dir, so the argument to rename must be $dir/* and not just *

Since you want to replace dir/8digits with dir/dir the replacement part of the regex should be $dir\/$dir

With the above changes the command looks like:

rename "s/$dir\/[0-9]{8}/$dir\/$dir/" $dir/*


回答2:

rename is actually a Perl script.

Here's how you could do it using only bash and mv:

#!/bin/bash

for dir in *; do
    if test -d "$dir"; then
        (
            cd $dir
            for file in *; do
                newfile=$dir.${file#*.}
                mv "$file" "$newfile"
            done
        )
    fi
done

First a script to reproduce your directory tree:

$ i=1
$ for dir in 000000{1..2}0; do
mkdir $dir
touch $dir/0000000$i.file{1..3}
i=$((i+1))
done
$ find .
.
./00000010
./00000010/00000001.file1
./00000010/00000001.file2
./00000010/00000001.file3
./00000020
./00000020/00000002.file3
./00000020/00000002.file2
./00000020/00000002.file1

And now showing the script working:

$ ../ren.sh
$ find .
.
./00000010
./00000010/00000010.file1
./00000010/00000010.file2
./00000010/00000010.file3
./00000020
./00000020/00000020.file1
./00000020/00000020.file2
./00000020/00000020.file3


回答3:

First, * in your find command is misplaced -- you need to give a directory to start searching. . is usual.

Second, $dir in your perl rename command won't be expanded by the shell because the whole string is quoted.

Third, the * you are handing to your perl rename command will expand to all the directories and files in your current working directory, which is probably not what you intended.

@Mikel's answer is much nicer than what I was working on, but I thought this might still be useful. :)