A simple mv command in a BASH script - bash

The aim of my script:
look at all the files in a directory ($Home/Music/TEST) and its sub-directories (they are music files)
find out what music genre each file belongs to
if the genre is Heavy, then move the file to another directory ($Home/Music/Output)
This is what I have:
#!/bin/bash
cd Music/TEST
for files in *
do
if [ -f "$files" ];then
# use mminfo to get the track info
genre=`mminfo "$files"|grep genre|awk -F: '{print $2}'|sed 's/^ *//g'|sed 's/[^a-zA-Z0-9\ \-\_]//g'`
if [ $genre = Heavy ] ;then
mv "$files" "~/Music/Output/$files"
fi
fi
done
Please tell me how to write the mv command. Everything I have tried has failed. I get errors like this:
mv: cannot move ‘3rd Eye Landslide.mp3’ to ‘/Music/Output/3rd Eye Landslide.mp3’: No such file or directory
Please don't think I wrote that mminfo line - that's just copied from good old Google search. It's way beyond me.

Your second argument to mv appears to be "~/Music/Output/$files"
If the ~ is meant to signify your home directory, you should use $HOME instead, like:
mv "$files" "$HOME/Music/Output/$files"
~ does not expand to $HOME when quoted.

By the look of it the problem occurs when you move the file to its destination.Please check that /Music/Output/ exits from your current directory.Alternatively use the absolute path to make it safe. Also it's a good idea not use space in the file-name.Hope this will helps.:)

Put this command before mv command should fix your problem.
mkdir -p ~/Music/Output

Related

How to check if a file exists or not and create/delete if does/does not exist in shell

In shell, I want to check if a file exists or not then create if it doesn't exist or delete if it exists. For this I need a one liner and am trying to do something like:
ls | awk '\filename\' <if exist delete else create>
I need the ls as my problem has some command that outputs a list of strings that need to be pipelined to awk then possibly touch/mkdir.
#!/bin/bash
if [ -z "$1" ] || [ ! -f "$1" ] # $1 is input filename and -f check if $1 is a regular file
then
rm "$1" #delete the file
else
touch "$1" #create the file
fi
save the file as filecreator.sh
change the permission to allow execution with sudo chmod a+rx
while running the script use ./filecreator.sh yourfile.extension
You can see the file in your directory.
Using oc projects and oc new-project instad of ls and touch as indicated in a comment.
oc projects |
while read -r proj; do
if [ -d "$proj" ]; then
rm -rf "$proj"
else
oc new-project "$proj"
fi
done
I don't think there is a useful way to write this as a one-liner. If you like, you can replace the newlines with semicolons, except after then and else.
You really should put your actual requirements in the question itself. ls is a superbly useless example because it cannot list a file which doesn't already exist, and you should not use ls in scripts at all.
rm yourfile 2>/dev/null || touch yourfile
If the file existed before, rm will succeed and erase the file, and the touch won't be executed. You end up with no file afterwards.
If the file did not exist before, rm will fail (but the error message is not visible, since it is directed to the bitbucket), and due to the non-zero exit code of rm, the touch will be executed. You end up with an empty file afterwards.
Caveat: If the file exists, but you don't have permissions to remove it, you won't notice this error, due to the redirection of stderr. Hence, for debugging and later diagnosis, it might be better to redirect stderr to some file instead.

Checkin if a Variable File is in another directory

I'm looking to check if a variable file is in another directory, and if it is, stop the script from running any farther. So far I have this:
#! /bin/bash
for file in /directory/of/variable/file/*.cp;
do
test -f /directory/to/be/checked/$file;
echo $?
done
I ran an echo of $file and see that it includes the full path, which would explain why my test doesn't see the file, but I am at a loss for how to move forward so that I can check.
Any help would be greatly appreciated!
Thanks
I think you want
#! /bin/bash
for file in /directory/of/variable/file/*.cp ; do
newFile="${file##*/}"
if test -f /directory/to/be/checked/"$newFile" ; then
echo "/directory/to/be/checked/$newFile already exists, updating ..."
else
echo "/directory/to/be/checked/$newFile not found, copying ..."
fi
cp -i "$file" /directory/to/be/checked/"$newFile"
done
Note that you can replace cp -i with mv -i and move the file, leaving no file left behind in /directory/of/variable/file/.
The -i option means interrogate (I think), meaning if the file is already there, it will ask you overwrite /directory/to/be/checked/"$newFile" (or similar) to which you must reply y. This will only happen if the file already exists in the new location.
IHTH
The command basename will give you just the file (or directory) without the rest of the path.
#! /bin/bash
for file in /directory/of/variable/file/*.cp;
do
test -f /directory/to/be/checked/$(basename $file);
echo $?
done

Shell Script to copy all files in a directory to a specified folder

I'm new in shell script and I am trying to figure out a way to write a script that copies all the files in the current directory to a directory specified from a .txt file and if there are matching names, it adds the current date in the form of FileName_YYYYMMDDmmss to the name of the file being copied to prevent overwritting.
Can someone help me out?
I saw thinking something along the lines of
#!/bin/bash
source=$pwd #I dont know wheter this actually makes sense I just want to
#say that my source directory is the one that I am in right now
destination=$1 #As I said I want to read the destination off of the .txt file
for i in $source #I just pseudo coded this part because I didn't figure it out.
do
if(file name exists)
then
copy by changing name
else
copy
fi
done
the problem is I have no idea how to check whether the name exist and copy and rename at the same time.
Thanks
How about this? I am supposing that the target directory is in the
file new_dir.txt.
#!/bin/bash
new_dir=$(cat new_dir.txt)
now=$(date +"%Y%m%d%M%S")
if [ ! -d $new_dir ]; then
echo "$new_dir doesn't exist" >&2
exit 1
fi
ls | while read ls_entry
do
if [ ! -f $ls_entry ]; then
continue
fi
if [ -f $new_dir/$ls_entry ]; then
cp $ls_entry $new_dir/$ls_entry\_$now
else
cp $ls_entry $new_dir/$ls_entry
fi
done
I guess this what you are looking for :
#!/bin/bash
dir=$(cat a.txt)
for i in $(ls -l|grep -v "^[dt]"|awk '{print $9}')
do
cp $i $dir/$i"_"$(date +%Y%m%d%H%M%S)
done
I assumed that a.txt contains only the name of the destination directory. If there are other entries, you should add some filter to the first statement(using grep or awk).
NB: I used full time stamp(YYYYMMDDHHmmss) instead of your YYYYMMDDmmss as it doesn't seem logical.

Getting relative paths in BASH

I already searched for this, but I guess there was no great demand on working with paths.
So I'm trying two write a bash script to convert my music collection using tta and cue files.
My directory structure is as following: /Volumes/External/Music/Just/Some/Dirs/Album.tta for the tta files and /Volumes/External/Cuesheets/Just/Some/Dirs/Album.cue for cue sheets.
My current approach is setting /Volumes/External as "root_dir" and get the relative path of the album.tta file to $ROOT_DIR/Music (in this case this would be Just/Some/Dirs/Album.tta), then add this result to $ROOT_DIR/Cuesheets and change the suffix from .tta to .cue.
My current problem is, that dirname returns paths as they are, which means /Volumes/External/Music/Just/Some/Dirs does not get converted to ./Just/Some/Dirs/ when my current folder is $ROOT_DIR/Music and the absolute path was given.
Add://Here is the script if anybody has similar problems:
#!/bin/bash
ROOT_DIR=/Volumes/External
BASE="$1"
if [ ! -f "$BASE" ]
then
echo "Not a file"
exit 1
fi
if [ -n "$2" ]
then
OUTPUT_DIR="$HOME/tmp"
else
OUTPUT_DIR="$2"
fi
mkfdir -p "$OUTPUT_DIR" || exit 1
BASE=${BASE#"$ROOT_DIR/Music/"}
BASE=${BASE%.*}
TTA_FILE="$ROOT_DIR/Music/$BASE.tta"
CUE_FILE="$ROOT_DIR/Cuesheets/$BASE.cue"
shntool split -f "${CUE_FILE}" -o aiff -t "%n %t" -d "${OUTPUT_DIR}" "${TTA_FILE}"
exit 0
If your Cuesheets dir is always in the same directory as your Music, you can just remove root_dir from the path, and what is left is the relative path. If you have the path to your album.tta in album_path (album_path=/Volumes/External/Music/Just/Some/Dirs/Album.tta) and your root_dir set(root_dir=/Volumes/External), just do ${album_path#$root_dir}. This trims root_dir from the front of album_path, so you are left with album_path=Just/Some/Dirs/Album.tta.
See bash docs for more information on bash string manipulation
EDIT:// Changed ${$album_path#$root_dir} to ${album_path#$root_dir}
Okay so I've tackled this a couple of ways in the past. I don't recommend screwing with paths and pwd environment variables, I've seen some catastrophic events because of it.
Here's what I would do
CURRENTDIR=/Volumes/External/Music # make sure you check the existence in your script
...
SEDVAL=$(echo $CURRENTDIR | sed s/'\/'/'\\\/'/g)
#run your loops for iterating through files
for a in $(find ./ -name \*ogg); do
FILE=`echo $a | sed s/$SEDVAL/./g` # strip the initial directory and replace it with .
convert_file $FILE # whatever action to be performed
done
If this is something you might do frequently I would actually just write a separate script just for this.

Recycle bin in bash problem

I need to make a recycle bin code using bash. Here is what I have done so far. My problem is that when I move a file with the same name into the trash folder it just overwrites the previous file. Can you give me any suggestions on how to approach this problem?
#!/bin/bash
mkdir -p "$HOME/Trash"
if [ $1 = -restore ]; then
while read file; do
mv $HOME/Trash/$2 /$file
done < try.txt
else
if [ $1 = -restoreall ]; then
mv $HOME/Trash/* /$PWD
else
if [ $1 = -empty ]; then
rm -rfv /$HOME/Trash/*
else
mv $PWD/"$1"/$HOME/Trash
echo -n "$PWD" >> /$HOME/Bash/try
fi
fi
fi
You could append the timestamp of the time of deletion to the filename in your Trash folder. Upon restore, you could strip this off again.
To add a timestamp to your file, use something like this:
DT=$(date +'%Y%m%d-%H%M%S')
mv $PWD/"$1" "/$HOME/Trash/${1}.${DT}"
This will, e.g., create a file like initrd.img-2.6.28-11-generic.20110615-140159 when moving initrd.img-2.6.28-11-generic.
To get the original filename, strip everything starting from the last dot, like with:
NAME_WITHOUT_TIMESTAMP=${file%.*-*}
The pattern is on the right side after the percentage char. (.* would also be enough to match.)
Take a look how trash-cli does it. It's written in Python and uses the same trash bin as desktop environments. Trash-cli is available at least in the big Linux distributions.
http://code.google.com/p/trash-cli/
Probably the easiest thing to do is simply add -i to the invocation of mv. That will prompt the user whether or not to replace. If you happen to have access to gnu cp (eg, on Linux), you could use cp --backup instead of mv.

Resources