Why cant I get mv to rename and copy file? - linux

The last thing I want to do in this script is take the userinput to rename the corresponding files to include .bak extension rather then .txt which will copy into a backup directory. I keep receiving an error messaging saying e.g.
mv: cannot stat '5.bak': No such file or directory
The snippet in question (right at the bottom of full code):
for i in ~/students/Stu$userinput/*_$userinput.txt;
do
mkdir -p ~/students/Backup; mv -- "$i" "${userinput%.txt}.bak" ~/students/Backup; #Change extension.
done
Full code:
#!/bin/bash
echo "Current User: $USER" >> system_info.txt #Inputs current user in .txt file.
echo "Current Directory: $PWD" >> system_info.txt #Inputs current user directory in .txt file.
#Creating the directory structure in the users home directory.
for i in {1..20}; #Create sub-directory of Stu from 1 to 20.
do
mkdir -p archive students/Stu${i}; #Two new dirctories created, with Stu having sub directories represented by {i},
done
i=1 #{i} to begin at 1.
until ((i>20)) #Each loop to check if i is greater than 20.
do
touch ~/students/Stu${i}/Notes_$i.txt #Creates a Notes page for every i up to 20.
touch ~/students/Stu${i}/Results_$i.txt #Similarily, creates a txt file for Results_$ up untill 20.
((i++))
done
for i in {1..20}; do #This is to echo the required sentence howcasing the current filename, user in the corresponding directory.
filename=~/students/Stu${i}/Notes_$i.txt
touch "$filename"
echo "The $(basename -- "$filename") file belonging to $USER was created in the Stu${i}." >> ~/students/Stu${i}/Notes_$i.txt
done
for i in {1..20}; do #This is to echo the required sentence howcasing the current filename, user in the corresponding directory.
filename=~/students/Stu${i}/Notes_$i.txt
touch "$filename"
echo "The $(basename -- "$filename") file belonging to $USER was created in the Stu${i}." >> ~/students/Stu${i}/Notes_$i.txt
done
for i in {1..20}; do
file_name=~/students/Stu${i}/Results_$i.txt
touch "$file_name"
echo "The $(basename -- "$file_name") file belonging to $USER was created in the Stu${i}." >> ~/students/Stu${i}/Results_$i.txt
done
while true;
do
echo -n "File to change: "
read userinput #Sets variable
if [ "$userinput" -ge 1 ] && [ "$userinput" -le 20 ];then #If userinput is greater than or equal to 1 or lss than or equal to 20/
echo "Valid number! File changed." #If fits crities, let user kniw
break
else #If critriea doesnt meet, try again.
echo "Invalid! File number must be between 1-20. Please try again."
fi
done
for i in ~/students/Stu$userinput/*_$userinput.txt;
do
mkdir -p ~/students/Backup; mv -- "$i" "${userinput%.txt}.bak" ~/students/Backup; #Change extension.
done
echo $?

The correct one would be
cp $i ~/students/Backup/$(basename ${i%.txt}.bak);
Note: mkdir -p ~/students/Backup is not needed to put in the loop

Related

Loop through file path to check if directory exists

I want to create a linux bash script to loop through the directory path to check if every directory does exists. This is just a simple example,
DIR="/etc/example/httpd/"
if [ -d "$DIR" ]; then
echo "$dir exists"
else
echo "$dir does not exists"
fi
I want to echo the output that the directory
/etc exists
/etc/example does not exists
/etc/example/httpd does not exists
Does it mean I have to perform a lot of cd commands in order to do this?
You are almost there.
The idea is to iterate the directory path elements by splitting them on the / delimiter.
#!/usr/bin/env bash
DIR="/etc/example/httpd"
dir=
# While there is a path element delimited by / to read
# or the element is not empty (but not followed by a trailing /)
while read -r -d/ e || [ -n "$e" ]; do
# If the element is not empty
if [ -n "$e" ]; then
# Postfix the element to the dir path with /
dir+="/$e"
if [ -d "$dir" ]; then
echo "$dir exists"
else
echo "$dir does not exists"
fi
fi
done <<<"$DIR"
Alternate method:
#!/usr/bin/env bash
DIR="/etc/example/httpd/"
# Set the Internal Field Separator to /
IFS=/
# Map the DIR path elements into an array arr
read -r -a arr <<<"$DIR"
# Starting at element 1 (skip element 0) and up to number of entries
for ((i=1; i<${#arr[#]}; i++)); do
# Combine dir path from element 1 to element i of the array
dir="/${arr[*]:1:i}"
if [ -d "$dir" ]; then
echo "$dir exists"
else
echo "$dir does not exists"
fi
done
And finally a POSIX shell grammar method:
#!/usr/bin/env sh
DIR="/etc/example/httpd/"
dir=
IFS=/
# Iterate DIR path elmeents delimited by IFS /
for e in $DIR; do
# If path element is not empty
if [ -n "$e" ]; then
# Append the element to the dir path with /
dir="$dir/$e"
if [ -d "$dir" ]; then
echo "$dir exists"
else
echo "$dir does not exists"
fi
fi
done
exit
I don't know if it will help you, but you can use Python, since you must be running the command in linux, it must have Python installed, to make a listing of files or folders in python is simple:
import os
DIR = "/etc/example/httpd/"
files = os.listdir(DIR) #Returns a list of files/folders from that directory

Delete file using linux

This code is that I want to give two directory and this code will look if these two directory contains two files that contains the same information, and asks me which file I want to delete .
I have written this code but I don't know how to write the code that will delete the file , please help
#!bin/bash
echo "give the first directory"
read firstdir
echo "give the second directory"
read seconddir
for i in ` ls $firstdir`
do
echo $i
t= `md5sum $firstdir/$i`
s= `md5sum $seconddir/$i`
if [ "$t" ! = "$s" ]
then
echo " of which directory will be eliminated? $i"
read direct
( here I want the code to delete the directory ex : delete direct/i )
fi
done
Replace:
echo " of which directory will be eliminated? $i"
read direct
( here I want the code to delete the directory ex : delete direct/i )
With:
echo "of which directory will be eliminated? $i:
1)$firstdir
2)$seconddir
"
read -p "(1/2)" direct
case $direct in
1)
rm -v $firstdir/$i
;;
2)
rm -v $seconddir/$i
;;
*)
echo "ERROR: bad value, 1 or 2 expected!" ; exit 1
esac
Ok, try this. I just made my own solution based on your requirements. I hope you like it. Thanks
#!/bin/bash
# check for a valid first directory
while true
do
echo "Please, enter the first directory"
read FIRST_DIR
if [ -d $FIRST_DIR ]; then
break
else
echo "Invalid directory"
fi
done
# check for a valid second directory
while true
do
echo "Please, give the second directory"
read SECOND_DIR
if [ -d $SECOND_DIR ]; then
break
else
echo "Invalid directory"
fi
done
for FILE in `ls $FIRST_DIR`
do
# make sure that only files will be avaluated
if [ -f $FILE ]; then
echo $SECOND_DIR/$FILE
# check if the file exist in the second directory
if [ -f $SECOND_DIR/$FILE ]; then
# compare the two files
output=`diff -c $FIRST_DIR/$FILE $SECOND_DIR/$FILE`
if [ ! $output ]; then
echo "Which file do you want to delete?
1)$FIRST_DIR/$FILE
2)$SECOND_DIR/$FILE
"
# read a choice
read -p "(1/2)" choice
# delete the chosen file
case $choice in
1)
rm -v $FIRST_DIR/$FILE
;;
2)
rm -v $SECOND_DIR/$FILE
;;
*)
echo "ERROR invalid choice!"
esac
fi
else
echo "There are no equal files in the two directories."
exit 1
fi
else
echo "There are no files to be evaluated."
fi
done

Export variables to another script

I am making 2 scripts. The first script is going to take a file, and then move it to a directory named "Trash". The second script will recover this file and send it back to it's original directory. So far I have the first script moving the file correctly.
Here is my code so far:
For delete.sh
FILE=$1
DATEDELETED=$(date)
DIRECTORY=$(pwd)
mv $1 Trash
echo $FILE
echo $DATEDELETED
echo $DIRECTORY
Output:
trashfile
Sun Mar 2 21:37:21 CST 2014
/home/user
For undelete.sh:
PATH=/home/user/Trash
for file in $PATH
do
$file | echo "deleted on" | date -r $file
done
echo "Enter the filename to undelete from the above list:"
EDIT: So I realized that I don't need variables, I can just list all the files in the Trash directory and edit the output to what I want. I'm having a little trouble with my for statement though, I'm getting these two errors: ./undelete.sh: line 6: date: command not found
./undelete.sh: line 6: /home/user/Trash: Is a directory. So I'm not exactly sure what I'm doing wrong in my for statement.
Here is the expected output:
file1 deleted on Tue Mar 16 17:15:34 CDT 2010
file2 deleted on Tue Mar 16 17:15:47 CDT 2010
Enter the filename to undelete from the above list:
Well I've accomplished what could be a workaround for what your scenario is trying to accomplish.
Basically you can enter echo "script2variable=$script1variable" >> script2.sh from script1.sh. Then use the source command to call that script later from any script you desire. Might have to just play with the theories involved.
Good Luck!
Delete Script file
#!/bin/bash
# delete.sh file
# Usage: ./delete.sh [filename]
#DATEDELETED=$(date) #not best solution for this kind of application
DIR=$(pwd)
fn=$1
#Specify your trash directory or partition
trash=~/trash
#Set path and filename for simple use in the script
trashed=$trash/$fn.tgz
#Send variables to new manifest script.
echo "#!/bin/bash" > $1.mf.sh
echo "DIR=$DIR" >> $1.mf.sh
# Questionable need?
#echo "DATEDELETED=$DATEDELETED" >> $1.mf.sh
echo "mv $1 $DIR" >> $1.mf.sh
echo Compressing
tar -cvpzf $trashed $1 $1.mf.sh
if [ $? -ne 0 ]; then
echo Compression Failed
else
echo completed trash compression successfully
echo Trashbin lists the file as $trashed
rm $1 -f
rm $1.mf.sh -f
echo file removed successfully
fi
exit 0
Restore Script File
#!/bin/bash
# restore.sh
# Usage: ./restore.sh
# filename not required for this script, use index selection
fn=$1
#SET LOCATION OF TRASH DIRECTORY
trash=~/trash
listfile=($(ls $trash))
#SET COUNTER FOR LISTING FILES = 0
i=0
#THIS IS JUST A HEADER FOR YOUR OUTPUT.
clear #cleanup your shell
echo -e INDEX '\t' Filename '\t' '\t' '\t' Date Removed
#Echo a list of files from the array with the counter.
for FILES in "${listfile[#]}"
do
echo -e $i '\t' $FILES '\t' "deleted on $(date -r $trash/$FILES)"
let "i += 1"
done
#Output total number of items from the ls directory.
echo -e '\n' $i file\(s\) found in the trash!
# 1 Offset for 1 = 0, 2 = 1, and so on.
let "i -= 1"
#Require input of a single, double, or triple digit number only.
#Loop back prompt if not a number.
while true;
do
read -p "Enter an index number for file restoration: " indx
case $indx in
[0-9]|[0-9][0-9]|[0-9][0-9][0-9] ) break ;;
* ) read -p "Please enter a valid number 0-$i: " indx ;;
esac
done
#
script=$(echo ${listfile[$indx]}|sed 's/\.tgz/\.mf.sh/g')
tar -xvpzf $trash/${listfile[$indx]}
rm $trash/${listfile[$indx]}
sleep 2
chmod +x $script
source $script
rm $script
Run the script with source
source <yourscript>
or
. ./<yourscript>
In your case
. ./delete.sh && ./undelete.sh
Hope this will help

Linux shell script : make a folder with the current date name

I am trying to make a simple backup script and i have problem creating a folder with the curent date for name
My script is that and basically the problem is on the last line
drivers=$(ls /media/)
declare -i c=0
for word in $drivers
do
echo "($c)$word"
c=c+1
done
read -n 1 drive
echo
c=0
for word in $drivers
do
if [ $c -eq $drive ]
then
backuppath="/media/$word/backup"
fi
c=c+1
done
echo "doing back up to $backuppath"
cp -r /home/stefanos/Programming $backuppath/$(date +%Y-%m-%d-%T)
Ouput:
(0)0362-BA96
(1)Data
(2)Windows
0
doing back up to /media/0362-BA96/backup
cp: cannot create directory `/media/0362-BA96/backup/2012-12-05-21:58:37': Invalid argument
The path is triply checked that is existing until /media/0362-BA96/
SOLVED:
Did what janisz said the final script looks like
drivers=$(ls /media/)
declare -i c=0
for word in $drivers
do
echo "($c)$word"
c=c+1
done
read -n 1 drive
echo
c=0
for word in $drivers
do
if [ $c -eq $drive ]
then
backuppath="/media/$word/backup"
fi
c=c+1
done
echo "doing back up to $backuppath"
backup(){
time_stamp=$(date +%Y_%m_%d_%H_%M_%S)
mkdir -p "${backuppath}/${time_stamp}$1"
cp -r "${1}" "${backuppath}/${time_stamp}$1"
echo "backup complete in $1"
}
#####################The paths to backup####################
backup "/home/stefanos/Programming"
backup "/home/stefanos/Android/Projects"
backup "/home/stefanos/Dropbox"
Trying changing it to:
time_stamp=$(date +%Y-%m-%d-%T)
mkdir -p "${backuppath}/${time_stamp}"
cp -r /home/stefanos/Programming "${backuppath}/${time_stamp}"
: is not valid on FAT (it is used to specify disk). Some of M$ invalid character works on GNU/Linux systems but it is safer to avoid them (just replace with .). Use following date format
date +%Y_%m_%d_%H_%M_%S
It should works on most file systems but it could be too long for MS DOS FAT. More info you will find here.

tar the files in a directory and put the archive in another directory

I'm trying to tar all of the files in a directory (echo 1) to a tar archive called [directory name].tar in the archive directory (second echo). Is this correct ?
#!/bin/bash
#Author
#Josh
++++++++++++++++++++++++++
echo "Please enter the name of a folder to archive"
++++++++++++++++++++++++++
echo "Please enter a foldername to store archives in"
++++++++++++++++++++++++++
touch fname
+++++++++++++++++++++++++
tar fname2.tar
dir_to_be_tarred=
while [ ! -d "$dir_to_be_tarred" ]; do
echo -n "Enter path to directory to be archived: " # -n makes "echo" not output an ending NEWLINE
read dir_to_be_tarred
if [ ! -d "$dir_to_be_tarred" ]; then # make sure the directory exists
echo "Directory \"$dir_to_be_tarred\" does not exist" # use quotes around the directory name in case user enter an empty line
fi
done
storage_dir=
while [ ! -d "$storage_dir" ]; do
echo -n "Enter path to directory where to store the archive: "
read storage_dir
if [ ! -d "$storage_dir" ]; then
echo "Directory \"$storage_dir\" does not exist"
fi
done
tarfile="$storage_dir"/`date '+%Y%m%d_%H%M%S'`.tar.gz # the tar archive is named "YYYYMMDD_HHMMSS.tar.gz"
tar cfz "$tarfile" "$dir_to_be_tarred"
echo 'Your archive is in:
'`ls -l "$tarfile"`

Resources