TheKojuEffect
TheKojuEffect

Reputation: 21081

Rename files in shell

I've folder and file structure like


Folder/1/fileNameOne.ext
Folder/2/fileNameTwo.ext
Folder/3/fileNameThree.ext
...

How can I rename the files such that the output becomes


Folder/1_fileNameOne.ext
Folder/2_fileNameTwo.ext
Folder/3_fileNameThree.ext
...

How can this be achieved in linux shell?

Upvotes: 0

Views: 3090

Answers (4)

TheKojuEffect
TheKojuEffect

Reputation: 21081

This solution from AskUbuntu worked for me.

Here is a bash script that does that:

Note: This script does not work if any of the file names contain spaces.

#! /bin/bash

# Only go through the directories in the current directory.
for dir in $(find ./ -type d)
do
    # Remove the first two characters. 
    # Initially, $dir = "./directory_name".
    # After this step, $dir = "directory_name".
    dir="${dir:2}"

    # Skip if $dir is empty. Only happens when $dir = "./" initially.
    if [ ! $dir ]
    then
        continue
    fi

    # Go through all the files in the directory.
    for file in $(ls -d $dir/*)
    do
        # Replace / with _
        # For example, if $file = "dir/filename", then $new_file = "dir_filename"
        # where $dir = dir
        new_file="${file/\//_}"

        # Move the file.
        mv $file $new_file
    done

    # Remove the directory.
    rm -rf $dir
done
  • Copy-paste the script in a file.
  • Make it executable using
chmod +x file_name
  • Move the script to the destination directory. In your case this should be inside Folder/.
  • Run the script using ./file_name.

Upvotes: 0

dogbane
dogbane

Reputation: 274532

Use a loop as follows:

while IFS= read -d $'\0' -r line
do
    mv "$line" "${line%/*}_${line##*/}"
done < <(find Folder -type f -print0)

This method handle spaces, newlines and other special characters in the file names and the intermediate directories don't necessarily have to be single digits.

Upvotes: 2

Jonathan Leffler
Jonathan Leffler

Reputation: 753475

How many different ways do you want to do it?

If the names contain no spaces or newlines or other problematic characters, and the intermediate directories are always single digits, and if you have the list of the files to be renamed in a file file.list with one name per line, then one of many possible ways to do the renaming is:

sed 's%\(.*\)/\([0-9]\)/\(.*\)%mv \1/\2/\3 \1/\2_\3%' file.list | sh -x

You'd avoid running the command through the shell until you're sure it will do what you want; just look at the generated script until its right.

There is also a command called rename — unfortunately, there are several implementations, not all equally powerful. If you've got the one based on Perl (using a Perl regex to map the old name to the new name) you'd be able to use:

rename 's%/(\d)/%/${1}_%' $(< file.list)

Upvotes: 2

fedorqui
fedorqui

Reputation: 289495

This may work if the name is always the same, ie "file":

for i in {1..3};
do
    mv $i/file ${i}_file
done

If you have more dirs on a number range, change {1..3} for {x..y}.

I use ${i}_file instead of $i_file because it would consider $i_file a variable of name i_file, while we just want i to be the variable and file and text attached to it.

Upvotes: 1

Related Questions