Renaming files in bash - bash

My directory has many files named as "20130101_temp.txt", "20130102_temp.txt", etc.
How do I remove the "_temp" in the names of all these files. i.e., rename 20130101_temp.txt to 20130101.txt.

Using bash:
for x in *_temp.txt
do
mv $x ${x%%_temp.txt}.txt
done
There's also a utility that comes with Perl (at least on Ubuntu) called rename which takes a regular expression, so you could accomplish the same thing with:
rename -n 's/_temp\.txt$/.txt/' *_temp.txt
The -n option initiates a "dry run" that will only show you what is going to be renamed. Remove it to actually perform the rename.

Using a for-loop with a glob to find the files and a parameter substitution to remove the _temp for moving:
for t in ????????_temp.txt; do
echo mv ${t} ${t/_temp/}
done
Remove the echo when you've tested that the output looks right on your system.

Try something like this:
for FILENAME in *_temp.txt; do
mv $FILENAME `echo $FILENAME | sed -e 's/_temp//'`
done
It is usually a good idea to try it out first with the mv replaced with an echo.

It's not a bash solution but since I encounter renaming tasks frequently while being way to lazy to think about a reasonable bash solution, I just got pyRenamer, a GUI tool that does things like that quite well. It's usually installable from the standard repositories.
dlundquists solution works quite well though.

This worked for me:
find . -depth -name '*_temp*' -execdir bash -c 'for f; do mv -i "$f" "${f//_temp/ }"; done' bash {} +

Related

Renaming bunch of files with xargs

I've been trying to rename a bunch of files in a proper order using xargs but to no avail. While digging around on piles of similar question, I found answers with the use of sed alongside xargs. Novice me wants to avoid the use of sed. I presume there must be some easier way around.
To be more specific, I've got some files as follows:
Abc.jpg
Def.jpg
Ghi.jpg
Jkl.jpg
and I want these to be renamed in an ordered way, like:
Something1.jpg
Something2.jpg
Something3.jpg
Something4.jpg
Could xargs command along with seq achieve this? If so, how do I implement it?
I don't know why anyone would try to engage sed for this. Probably not xargs or seq, either. Here's a pure-Bash one-liner:
(x=1; for f in *.jpg; do mv "$f" "Something$((x++)).jpg"; done)
At its core, that's a for loop over the files you want to rename, performing a mv command on each one. The files to operate on are expressed via a single glob expression, but you could also name them individually, use multiple globs, or use one of a variety of other techniques. Variable x is used as a simple counter, initialized to 1 before entering the loop. $((x++)) expands to the current value of x, with the side effect of incrementing x by 1. The whole thing is wrapped in parentheses to run it in a subshell, so that nothing in it affects the host shell environment. (In this case, that means it does not create or modify any variable x in the invoking shell.)
If you were putting that in a script instead of typing it on the command line then it would be more readable to split it over several lines:
(
x=1
for f in *.jpg; do
mv "$f" "Something$((x++)).jpg"
done
)
You can type it that way, too, if you wish.
This is an example of how to find, number and rename jpgs.
Regardless of how you use the find (what options you need. recursive, mindepth, maxdepth, regex, ...).
You can add numbers to find ouput with nl and use number and file as 2 arguments for xargs $1, $2
$ find . -type f -name "*.jpg" |nl| xargs -n 2 bash -c 'echo mv "$2" Something"$1".jpg' argv0
the echo echo mv ... will show this
mv ./Jkl.jpg Something1.jpg
mv ./Abc.jpg Something2.jpg
mv ./Def.jpg Something3.jpg
Using sort and testing the number of arguments
$ find . -type f -name "*.jpg" |sort|nl| xargs -n 2 bash -c '[ "$#" -eq 2 ] && echo mv "$2" Something"$1".jpg' argv0
mv ./Abc.jpg Something1.jpg
mv ./Def.jpg Something2.jpg
mv ./Jkl.jpg Something3.jpg

Rename all files in a directory by omitting last 3 characters

I am trying to write a bash command that will rename all the files in the current directory by omitting the last 3 characters. I am not sure if it is possible thats why I am asking here.
I have a lots of files named like this : 720-1458907789605.ts
I need to rename all of them by omitting last 3 characters to obtain from 720-1458907789605.ts ---> 720-1458907789.ts for all files in the current directory.
Is it possible using bash commands? I am new to bash scripts.
Thank you!
Native bash solution:
for f in *.ts; do
[[ -f "$f" ]] || continue # if you do not need to rename directories
mv "$f" "${f:: -6}.ts"
done
This solution is slow if you have really many files: star-expansion in for will take up memory and time.
Ref: bash substring extraction.
If you have a really large data set, a bit more complex but faster solution will be:
find . -type f -name '*.ts' -depth 1 -print0 | while read -d $\0 f; do
mv "$f" "${f%???.ts}.ts"
done
With Larry Wall's rename:
rename -n 's/...\.ts$/.ts/' *.ts
If everything looks okay remove dry run option -n.

How to rename files in current directory and its subdirectories using bash script?

I'm able to use the 'rename' command to add the missing character to all filenames in the current directory like this:
echo "Renaming files..."
rename -v "s/^abcd124(.+)/abcd1234$1/" *.wav.gz;
echo "Done."
However, I'd like to do this for the current directory and all its subdirectories. I tried this:
echo "Renaming files..."
for dir in $(find ./ -type d); do
rename -v "s/^$dir\/abcd124(.+)/$dir\/abcd1234$1/" *.wav.gz;
done;
echo "Done."
However, if the $dir variable contains any of these special characters: {}[]()^$.|*+?\ then they are not escaped properly with \ and my script fails.
What would be the best way to solve this problem? Also, what do you guys think of using awk to solve this problem (advantages/disadvantages?)
You can also try:
find . -name "*.wav.gz" | xargs rename -v "s/abcd124*/abcd1234$1/"
It works on newer Unix systems with "xargs" command available. Note that I edited the regular expression slightly.
Try:
find ./ -type d -execdir rename -v "s/^abcd124(.+)/abcd1234\1/" *.wav.gz ";"
Find does already provide an iterator over your files - you don't need for around it or xargs behind , which are often seen. Well - in rare cases, they might be helpful, but normally not.
Here, -execdir is useful. Gnu-find has it; I don't know if your find has it too.
But you need to make sure not to have a *.wav.gz-file in the dir you're starting this command, because else your shell will expand it, and hand the expanded names over to rename.
Note: I get an warning from rename, that I should replace \1 with $1 in the regex, but if I do so, the pattern isn't catched. I have to use \1 to make it work.
Here is another approach. Why at all search for directories, if we search for wav.gz-files?
find . -name "*.wav.gz" -exec rename -v "s/^abcd124(.+)/abcd1234\1/" {} ";"
In bash 4:
shopt -s globstar
rename -v "s/^$dir\/abcd124(.+)/$dir\/abcd1234$1/" **/*.wav.gz;
Just be aware that Gentoo Linux has its rename utility points to
http://developer.berlios.de/project/showfiles.php?group_id=413
by its ebuild
http://sources.gentoo.org/cgi-bin/viewvc.cgi/gentoo-x86/sys-apps/rename/rename-1.3.ebuild?view=markup
for Debian or maybe Ubuntu,
rename is /usr/bin/prename, which is a perl script
See rename --help before your move.

Glob renaming in bash

I'm fairly new to bash so sorry if this is kind of a basic question. I was trying to rename a bunch of mp3 files to prepend 1- to their filenames, and mv *.mp3 1-*.mp3 didn't work unfortunately. So I tried to script it, first with echo to test the commands:
for f in *.mp3 ; do echo mv \'$f\' \'1-$f\'; done
Which seems to output the commands that I like, so I removed the echo, changing the command to
for f in *.mp3 ; do mv \'$f\' \'1-$f\'; done
Which failed. Next I tried piping the commands onward like so
for f in *.mp3 ; do echo mv \'$f\' \'1-$f\'; done | /bin/sh
Which worked, but if anyone could enlighten me as to why the middle command doesn't work I would be interested to know. Or if there is an more elegant one-liner that would do what I wanted, I would be interested to see that too.
I think you have to change the command to
for f in *.mp3 ; do mv "$f" "1-$f"; done
Otherwise you would pass something like 'file1.mp3' and '1-file1.mp3' to mv (including the single quotes).
Dry run:
rename -n 's/^/1-/' *.mp3
Remove the -n if it looks correct to run the command. man rename for details.

Unable to convert dot-files to non-dotfiles safely

I run unsuccessfully in Mac
mv .* *
and
mv .* ./*
My files disappeared into thin air.
How can you convert dot-files to non-dotfiles safely?
for i in `ls -d .*`; do mv $i "`echo $i | sed 's/^.//'`"; done
or, much easier,
rename 's/^.//' `ls -d .*`
if your system have got it.
In zsh, you could just use .* safely, but in bash you'll have to use ls -d .*
You can't use mv to rename multiple files like that. What you want is mmv (get it here).
mmv .\* \#1
You have to escape the asterisk to prevent bash from expanding it. Use the -n flag to do a test run to make sure what will happen is what you want.
You could also do this in shell scripting but I much prefer mmv because the -n flag shows what it would do. You'd have to alter your script to echo instead of mv, which seems more dangerous than dropping the -n flag (especially when you get more complicated.
The tricky part about this is selecting dotfiles without selecting "." and "..".
ls .??* is sometimes used for this, since it forces the filenames to be three or more characters long. There is a risk though, of overlooking a dotfile with a short name, such as ".x"
ls -d .* prevents directories from being expanded, but it doesn't filter out "." or ".."
The find command could be used, as in find . -maxdepth 1 -type f -name '.*'. The maxdepth limits it to the current directory and not subdirectories. The -type f limits it to files, eliminating directories such as "." and "..". Then again, maybe you want to rename the .ssh directory to ssh.
Here's an alternative that selects dotfiles while avoiding "." and "..".
ls -A | sed -n 's/^\.\(.*\)/mv ".\1" "\1"/p' | bash
The -A lists all files and dotfiles, yet eliminates "." and ".." for us. Then the sed command selects only those lines with "." as the first character, and prints out appropriate "mv" commands, complete with quotes in case you have a bizarre dotfilename with a space in it.
Run it without the "| bash" first, to see what mv commands are generated.
i don't know what type of system you're on, but it looks unix like, i would do
ls -1 .?* | cut -b1- | xargs -i{} mv .{} {}
this lists, everything that starts with a ., but isn't . or .., then cut the first column off, then pipe that list to a move command
In Linux, there is usually a rename utility available (a perl script, if I am not mistaken):
rename 's/^.//' .*
It is available on a Mac. You can install it by following tips at here.
Even simpler:
for x in .*; do mv $x ${x/./}; done

Resources