How to rename all files in a directory from $filename into $Backupfilename - bash

I have a folder called, evaluation, located in, /home/evaluation, which contains this :
Geography
Math
History
English
How do I rename every file inside of this folder, into something like this :
BackupGeography
BackupMath
BackupHistory
BackupEnglish
Here is what I have tried so far :
for file in /home/evaluation/*
do
mv "$file" "${file//Backup}"
done
But it doesn't work unfortunately.

Try this:
for file in /home/evaluation/*
do
mv -i "$file" "$(dirname "$file")/Backup$(basename "$file")"
done
Explanation: dirname gets the directory name (e.g. dirname /home/evaluation/Geography prints "/home/evaluation"), and basename gets the file name without the path (e.g. dirname /home/evaluation/Geography prints "Geography"). So
... "$(dirname "$file")/Backup$(basename "$file")"
--> "/home/evaluation" + "/Backup" + "Geography"
--> "/home/evaluation/BackupGeography"
(Note: + is not a shell operator. At least, not like this. I'm just illustrating how it's parsed.)
Oh, and mv -i will ask what to do if there's a name conflict. Without the -i, it'll silently and irreversibly delete one of the conflicting files. Using mv for bulk moves without -i (or -n) always makes me nervous.

You can do
for file in /home/evaluation/*
do
mv "$file" `dirname "$file"`/Backup`basename "$file"`
done

Related

Rename a file when I don't know its name - shell script

I am trying to rename a file which is the only file in a directory.
It is a podcast download which changes name each day so I don't know what it is called but it always ends in .MP3
I want to rename it to news.mp3
I have tried the following based on another solution on this site but it appends the news to the file
#!/bin/sh
for file in *.MP3; do
mv "$file" "${file/.MP3/news.mp3}"
done
If it's the only file in the directory you can just write the following command:
mv directory_name/* directory_name/news.mp3
In case there are few files or if dir is empty:
shopt -s nullglob
src="/path/to/dir/with/files"
dst="/destanation/folder"
i=1
cd "$src"
for f in *; do
mv "$f" "$dst/new_name_$((i++))"
done

move every file from every folder to specific folder

I am trying to write in shell script to run this..
I guess it requires for syntax or find syntax..
but I am stuck dealing with scan every folder..
I have tried with "find" -maxdepth 1 -name "*.jpg | mv " but failed...
for every jpg files in every dir (folder1, folder2, folder3...folder5...etc)
move files to target dir which is parent dir.
if file name duplicated, move to dup dir.
DIR tree looks like this
Something like
for f in folder*/*.jpg; do
if [ -e "$(basename "$f")" ]; then
mv "$f" dup/
else
mv "$f" .
fi
done
run from the parent directory. Just iterates over every jpg in the folder subdirectories, moving to one place or another depending on if a file with that name already exists or not.
Slightly more efficient bash version:
for f in folder*/*.jpg; do
if [[ -e ${f##*/} ]]; then
mv "$f" dup/
else
mv "$f" .
fi
done

Collapse nested directories in bash

Often after unzipping a file I end up with a directory containing nothing but another directory (e.g., mkdir foo; cd foo; tar xzf ~/bar.tgz may produce nothing but a bar directory in foo). I wanted to write a script to collapse that down to a single directory, but if there are dot files in the nested directory it complicates things a bit.
Here's a naive implementation:
mv -i $1/* $1/.* .
rmdir $1
The only problem here is that it'll also try to move . and .. and ask overwrite ./.? (y/n [n]). I can get around this by checking each file in turn:
IFS=$'\n'
for file in $1/* $1/.*; do
if [ "$file" != "$1/." ] && [ "$file" != "$1/.." ]; then
mv -i $file .
fi
done
rmdir $1
But this seems like an inelegant workaround. I tried a cleaner method using find:
for file in $(find $1); do
mv -i $file .
done
rmdir $1
But find $1 will also give $1 as a result, which gives an error of mv: bar and ./bar are identical.
While the second method seems to work, is there a better way to achieve this?
Turn on the dotglob shell option, which allows the your pattern to match files beginning with ..
shopt -s dotglob
mv -i "$1"/* .
rmdir "$1"
First, consider that many tar implementations provide a --strip-components option that allows you to strip off that first path. Not sure if there is a first path?
tar -tf yourball.tar | awk -F/ '!s[$1]++{print$1}'
will show you all the first-level contents. If there is only that one directory, then
tar --strip-components=1 -tf yourball.tar
will extract the contents of that directory in tar into the current directory.
So that's how you can avoid the problem altogether. But it's also a solution to your immediate problem. Having extracted the files already, so you have
foo/bar/stuff
foo/bar/.otherstuff
you can do
tar -cf- foo | tar --strip-components=2 -C final_destination -xf-
The --strip-components feature is not part of the POSIX specification for tar, but it is on both the common GNU and OSX/BSD implementations.

mv using filename expansion operation caused files to disappear

I have a bunch of files named
index.html.1
index.html.2
...
I tried to write a bash script to fix all of their extensions
for file in *.html.*
do
mv "$file" "${file%.html.*}.jpg"
done
which made all of the files disappear.
What have I done?!
You have moved each index.html file, one at a time, to the same target filename. Unfortunately all but the last has now been overwritten.
touch index.html.{1,2,3,4,5}
for file in *.html.*; do echo mv "$file" "${file%.html.*}.jpg"; done
Output
mv index.html.1 index.jpg
mv index.html.2 index.jpg
mv index.html.3 index.jpg
mv index.html.4 index.jpg
mv index.html.5 index.jpg

Batch mv or rename in bash script - append date as a suffix

After much searching and trial and error, I'm unable to do a batch mv or rename on a directory of files. What I'd like to do is move or rename all files in a directory so that the mv'd or renamed file has $date (+ '%Y%d%m') added to the original suffix.
All the original files have unique prefixes but are either .xml or .txt so I'd like to go from org_prefix.org_suffix -> org_prefix.org_suffix.DATE
I've tried this:
$ mv /directory/* /directory/*$(date (+ '%Y%m%d')
but always get /directory/*.actualdate' is not a directory error.
I've tried this:
$ for f in *; do mv $ $f.$(date +'_%m%d%y'); done
but I get mv: cannot stat '$'; No such file or directory
Lastly, I've even tried this:
$ rename 's/*/.test/' *
just to see if I could change all the files to org_prefix.test but nothing happens (no errors, nada, zip)
Any help greatly appreciated.
The proper way to loop through files (and e.g., print their name) in the current directory is:
for file in *; do
echo "$file"
done
How will you append the date? like so, of course:
for file in *; do
echo "$file.$(date +%Y%m%d)"
done
And how are you going to do the move? like so, of course:
for file in *; do
mv -nv -- "$file" "$file.$(date +%Y%m%d)"
done
I've added:
-v so that mv be verbose (I like to know what's happening and it always impresses my little sister to watch all these lines flowing on the screen).
-n so as to no overwrite an otherwise existing file. Safety first.
-- just in case a file name starts with a hyphen: without --, mv would confuse with an option. Safety first.
If you just want to look through the files with extension .banana, replace the for with:
for file in *.banana; do
of for files that contain the word banana:
for file in *banana*; do
and so on.
Keep up with the bananas!
$ mv /directory/* /directory/*$(date (+ '%Y%m%d')
This does not work, because the * is expanded to a list of all files, so after the expansion the command will be something like:
mv /directory/file1 /directory/file2 /directory/file3 /directory/file1_date /directory/file1_date ...
So you have specified many destinations, but the syntax for mv allows only one single destination.
for f in *; do mv $ $f.$(date +'_%m%d%y'); done
Here you forgot the f after the $, that's why you get the error message.
for f in *; do mv $f $f.$(date +'%m%d%y'); done
I think this should work now, but don't forget to quote all the variables!
Finally:
for f in *; do mv "$f" "$f.$(date +'%m%d%y')"; done
Edit: When there are characters directly after a variable, it's good practice to use {} to make clear that they are not part of the variable name:
for f in *; do mv "$f" "${f}.$(date +'%m%d%y')"; done

Resources