[linux] Find multiple files and rename them in Linux

I am having files like a_dbg.txt, b_dbg.txt ... in a Suse 10 system. I want to write a bash shell script which should rename these files by removing "_dbg" from them.

Google suggested me to use rename command. So I executed the command rename _dbg.txt .txt *dbg* on the CURRENT_FOLDER

My actual CURRENT_FOLDER contains the below files.

CURRENT_FOLDER/a_dbg.txt
CURRENT_FOLDER/b_dbg.txt
CURRENT_FOLDER/XX/c_dbg.txt
CURRENT_FOLDER/YY/d_dbg.txt

After executing the rename command,

CURRENT_FOLDER/a.txt
CURRENT_FOLDER/b.txt
CURRENT_FOLDER/XX/c_dbg.txt
CURRENT_FOLDER/YY/d_dbg.txt

Its not doing recursively, how to make this command to rename files in all subdirectories. Like XX and YY I will be having so many subdirectories which name is unpredictable. And also my CURRENT_FOLDER will be having some other files also.

This question is related to linux bash shell scripting suse

The answer is


Scipt above can be written in one line:

find /tmp -name "*.txt" -exec bash -c 'mv $0 $(echo "$0" | sed -r \"s|.txt|.cpp|g\")' '{}' \;

You can use this below.

rename --no-act 's/\.html$/\.php/' *.html */*.html

If you just want to rename and don't mind using an external tool, then you can use rnm. The command would be:

#on current folder
rnm -dp -1 -fo -ssf '_dbg' -rs '/_dbg//' *

-dp -1 will make it recursive to all subdirectories.

-fo implies file only mode.

-ssf '_dbg' searches for files with _dbg in the filename.

-rs '/_dbg//' replaces _dbg with empty string.

You can run the above command with the path of the CURRENT_FOLDER too:

rnm -dp -1 -fo -ssf '_dbg' -rs '/_dbg//' /path/to/the/directory

classic solution:

for f in $(find . -name "*dbg*"); do mv $f $(echo $f | sed 's/_dbg//'); done

find -execdir rename

https://stackoverflow.com/a/16541670/895245 works directly only for suffixes, but this will work for arbitrary regex replacements on basenames:

PATH=/usr/bin find . -depth -execdir rename 's/_dbg.txt$/_.txt' '{}' \;

or to affect files only:

PATH=/usr/bin find . -type f -execdir rename 's/_dbg.txt$/_.txt' '{}' \;

-execdir first cds into the directory before executing only on the basename.

Tested on Ubuntu 20.04, find 4.7.0, rename 1.10.

Convenient and safer helper for it

find-rename-regex() (
  set -eu
  find_and_replace="$1"
  PATH="$(echo "$PATH" | sed -E 's/(^|:)[^\/][^:]*//g')" \
    find . -depth -execdir rename "${2:--n}" "s/${find_and_replace}" '{}' \;
)

GitHub upstream.

Sample usage to replace spaces ' ' with hyphens '-'.

Dry run that shows what would be renamed to what without actually doing it:

find-rename-regex ' /-/g'

Do the replace:

find-rename-regex ' /-/g' -v

Command explanation

The awesome -execdir option does a cd into the directory before executing the rename command, unlike -exec.

-depth ensure that the renaming happens first on children, and then on parents, to prevent potential problems with missing parent directories.

-execdir is required because rename does not play well with non-basename input paths, e.g. the following fails:

rename 's/findme/replaceme/g' acc/acc

The PATH hacking is required because -execdir has one very annoying drawback: find is extremely opinionated and refuses to do anything with -execdir if you have any relative paths in your PATH environment variable, e.g. ./node_modules/.bin, failing with:

find: The relative path ‘./node_modules/.bin’ is included in the PATH environment variable, which is insecure in combination with the -execdir action of find. Please remove that entry from $PATH

See also: https://askubuntu.com/questions/621132/why-using-the-execdir-action-is-insecure-for-directory-which-is-in-the-path/1109378#1109378

-execdir is a GNU find extension to POSIX. rename is Perl based and comes from the rename package.

Rename lookahead workaround

If your input paths don't come from find, or if you've had enough of the relative path annoyance, we can use some Perl lookahead to safely rename directories as in:

git ls-files | sort -r | xargs rename 's/findme(?!.*\/)\/?$/replaceme/g' '{}'

I haven't found a convenient analogue for -execdir with xargs: https://superuser.com/questions/893890/xargs-change-working-directory-to-file-path-before-executing/915686

The sort -r is required to ensure that files come after their respective directories, since longer paths come after shorter ones with the same prefix.

Tested in Ubuntu 18.10.


small script i wrote to replace all files with .txt extension to .cpp extension under /tmp and sub directories recursively

#!/bin/bash

for file in $(find /tmp -name '*.txt')
do
  mv $file $(echo "$file" | sed -r 's|.txt|.cpp|g')
done

For renaming recursively I use the following commands:

find -iname \*.* | rename -v "s/ /-/g"

with bash:

shopt -s globstar nullglob
rename _dbg.txt .txt **/*dbg*

Examples related to linux

grep's at sign caught as whitespace How to prevent Google Colab from disconnecting? "E: Unable to locate package python-pip" on Ubuntu 18.04 How to upgrade Python version to 3.7? Install Qt on Ubuntu Get first line of a shell command's output Cannot connect to the Docker daemon at unix:/var/run/docker.sock. Is the docker daemon running? Run bash command on jenkins pipeline How to uninstall an older PHP version from centOS7 How to update-alternatives to Python 3 without breaking apt?

Examples related to bash

Comparing a variable with a string python not working when redirecting from bash script Zipping a file in bash fails How do I prevent Conda from activating the base environment by default? Get first line of a shell command's output Fixing a systemd service 203/EXEC failure (no such file or directory) /bin/sh: apt-get: not found VSCode Change Default Terminal Run bash command on jenkins pipeline How to check if the docker engine and a docker container are running? How to switch Python versions in Terminal?

Examples related to shell

Comparing a variable with a string python not working when redirecting from bash script Get first line of a shell command's output How to run shell script file using nodejs? Run bash command on jenkins pipeline Way to create multiline comments in Bash? How to do multiline shell script in Ansible How to check if a file exists in a shell script How to check if an environment variable exists and get its value? Curl to return http status code along with the response docker entrypoint running bash script gets "permission denied"

Examples related to scripting

What does `set -x` do? Creating an array from a text file in Bash Windows batch - concatenate multiple text files into one Raise error in a Bash script How do I assign a null value to a variable in PowerShell? Difference between ${} and $() in Bash Using a batch to copy from network drive to C: or D: drive Check if a string matches a regex in Bash script How to run a script at a certain time on Linux? How to make an "alias" for a long path?

Examples related to suse

Find multiple files and rename them in Linux On linux SUSE or RedHat, how do I load Python 2.7 Graphical DIFF programs for linux