So I have a script that adds 2 films together using the audio from the $1.audio file. What I would like to do is rename any file in the directory with:
*.mp4 To:
*.audio Keeping original file name.
You can use the rename command. It's not portable, but it exists in different forms in different distributions.
In CentOS/RHEL and probably Fedora:
rename .mp4 .audio *.mp4 Should do it. From man rename on CentOS 6:
SYNOPSIS rename from to file... rename -V DESCRIPTION rename will rename the specified files by replacing the first occur- rence of from in their name by to. In Ubuntu and probably any Debian variant:
rename 's/\.mp4$/.audio/' *.mp4 should do it. From man rename on Ubuntu 14.04:
SYNOPSIS rename [ -v ] [ -n ] [ -f ] perlexpr [ files ] DESCRIPTION "rename" renames the filenames supplied according to the rule specified as the first argument. The perlexpr argument is a Perl expression which is expected to modify the $_ string in Perl for at least some of the filenames specified. If a given filename is not modified by the expression, it will not be renamed. If no filenames are given on the command line, filenames will be read via standard input. For example, to rename all files matching "*.bak" to strip the extension, you might say rename 's/\.bak$//' *.bak rename differs widely from distribution to distribution even for simple use cases, so I said it's "not portable". find, on the other hand (see jilliagre's answer), is very portable as it will work in any Linux distribution you're likely to ever encounter. Here is a fast and portable solution still handling oddly named files :
find . -name "*.mp4" -exec sh -c 'for i do mv -- "$i" "${i%.mp4}.audio"; done' sh {} + rename is definitely more readable. Use this for loop:
for f in *; do [ -f "$f" ] && mv -v -- "$f" "${f%.mp3}.audio" done for i in * loops trough all files and directories (except dot-files) in the current working directory and stores the current processed file in $f [ -f "$f" ] checks if it's a regular filemv -v renames the file (-- is that the filenames will not be interpreted as arguments by mistake)${f%.mp3}.audio removes the .mp3 extension and adds the .audio extension (Parameter Expansion)rename. Here is a solution that uses find, sed, and xargs. This solution works even if there are spaces in the name.
It first gets the files using find. Then, gets the base name of the file using sed. Finally, it does the move to change the extension.
Note the code below is multi-line for clarity. You should probably execute it in one line.
# split into three lines for clarity # should execute as one line find . -maxdepth 1 -name '*.mp4' | sed -r 's/.*\/([^/]+)\.mp4/\1/g' | xargs -ix mv "x.mp4" "x.audio" Below is an alternative solution using basename. This solution may work with names containing spaces (have not tested this one).
It first gets all the files with .mp4 extension, then gets the base name, and finally renames each with the audio extension.
# split into three lines for clarity # should execute as one line find . -maxdepth 1 -name '*.mp4' -print0 | xargs -0 -ix basename "x" .mp4 | xargs -ix mv "x.mp4" "x.audio" You can use
for file in `ls *.mp4`; { mv $file `echo $file | sed 's/.mp4/.audio/g'`; } ls. for-loop construct is that? It doesn't work in dash, but works in bash and zsh. I vaguely remember seeing this syntax before, but it's been literally decades ago. Is it a ksh thing? It's really kind of neat, substitute { for do, and } for done.