Check if arguments[files] exist or not in bash - bash

This is part of my script:
#!/bin/bash
USAGE(){
echo "Usage: ./`basename $0` <File1> <File2>"
}
if [ "$#" -ne "2" ]; then
USAGE
exit 1
fi
if [ ! -f "$1" ]; then
echo "The file \"$1\" does not exist!"
exit 1
fi
if [ ! -f "$2" ]; then
echo "The file \"$2\" does not exist!"
exit 1
fi
I want to check if file1 does not exist prints:
The file "file1" does not exist!
if file2 does not exist prints:
The file "file2" does not exist!
If both does not exist prints:
The files "file1" and "file2" don't exist!
How can I do that?
I want to know what the most logical (STANDARD) method is.

Of course you can do that... . There are many ways to obtain this. The most simple maybe:
if [ ! -f "$1" ] && [ ! -f "$2" ]; then
echo "The files \"$1\" and \"$2\" do not exist!"
exit 1
else
if [ ! -f "$1" ]; then
echo "The file \"$1\" does not exist!"
exit 1
fi
if [ ! -f "$2" ]; then
echo "The file \"$2\" does not exist!"
exit 1
fi
fi
If you don't want to do the checks two time, you can work with variables; something like this:
if [ ! -f "$1" ]; then
NOT1=1
fi
if [ ! -f "$1" ]; then
NOT2=1
fi
if [ -n "$NOT1" ] && [ -n "$NOT2" ]
....

You could do it like this so you only have to test each file once:
status=""
for file; do
[ -f "$file" ]
status+=$?
done
case $status in
11)
echo "The files \"$1\" and \"$2\" do not exist!"
exit 1
;;
10)
echo "The file \"$1\" does not exist!"
exit 1
;;
01)
echo "The file \"$2\" does not exist!"
exit 1
;;
esac

The logical is
if [ ! -f "$1" ]; then
if [ ! -f "$2" ]; then
echo "The files \"$file1\" and \"$file2\" don't exist!"
exit 1
else
echo "The file \"$1\" does not exist!"
exit 1
fi
fi
if [ ! -f "$2" ]; then
echo "The file \"$2\" does not exist!"
exit 1
fi
The readable is
if [ ! -f "$1" -a ! -f "$2" ]; then
echo "The files \"$file1\" and \"$file2\" don't exist!"
exit 1
fi
if [ ! -f "$1" ]; then
echo "The file \"$1\" does not exist!"
exit 1
fi
if [ ! -f "$2" ]; then
echo "The file \"$2\" does not exist!"
exit 1
fi
The readable is preferred.
Also not testing for existence twice as Chris Maes said could be logical too.

Simplified for Bash:
#!/bin/bash
if [[ $# -ne 2 ]]; then
echo "Usage: ${0##*/} <File1> <File2>"
elif [[ ! -f $1 && ! -f $2 ]]; then
echo "The files \"$1\" and \"$2\" don't exist!"
elif [[ ! -f $1 ]]; then
echo "The file \"$1\" does not exist!"
elif [[ ! -f $2 ]]; then
echo "The file \"$2\" does not exist!"
fi

You can use this additional condition:
if [ ! -f "$1" ] && [ ! -f "$2" ]; then
echo "Both files does not exist!"
exit 1
fi
I'm not sure you need that though. The two conditions you have, for first and second file, will be informative enough.
Alternatively, you can use just one condition by using logical OR ||. I'd suspect users wouldn't have an issue with understanding their misues of the script:
if [ ! -f "$1" ] || [ ! -f "$2" ]; then
USAGE
exit 1
fi

Related

Semaphore thinks lock file already exists

I'm using link to create a semaphore - the idea is to lock out of writing to a db.
Here I have a script to create a table in a database:
#!/bin/bash
if [ "$#" -lt 3 ]; then
echo "Not enough parameters"
exit 1
elif [ "$#" -gt 3 ]; then
echo "Too many parameters"
exit 1
fi
if [ ! -d "$1" ]; then
echo "That database doesn't exist!"
exit 1
fi
./P.sh $1
if [ -f "$1/$2.txt" ]; then
echo "That table already exists!"
./V.sh $1
exit 1
else
touch "$1/$2.txt"
fi
./V.sh $1
echo "$3" > "$1/$2.txt"
echo "Ok, table created"
exit 0
Here's my P file:
#!/bin/bash
if [ -z "$1" ]; then
echo "Usage $0 mutex-name"
exit 1
elif [ ! -e "$1" ]; then
echo "Target for the lock must exist"
exit 2
else
while ! ln "$1" "$1.lock"; do
sleep 1
done
exit 0
fi
and my V:
#! /bin/bash
if [ -z "$1" ]; then
echo "Usage $1 mutex-name"
exit 1
else
rm "$1.lock"
exit 0
fi
let's say I create a table by running ./create_table people footballers age,height
This should create a file footballers.lock (created by P) and then once the writing has happened the V should remove it. But for some reason the P thinks that the .lock file already exists, and it definitely doesn't.
Can anyone spot what's going wrong?
Found it - you can't use ln on directories...

sed command in Solaris server

I have many javascript files in my solaris server which have some debug, print and trace statements which I want to comment. There are hundreds of file like this.
I have found a script to do this but the problem is the script is removing the urhk_b2k_printRepos statement instead of commenting it. The script is as below:
if [ $# -ne 2 ]
then
echo "usage: prdel <script file name> <directory in which scripts are present>"
exit 1
fi
file=$1
dir=$2
if [ ! -s ${file} ]
then
echo "script file ${file} either does not exist or is empty (zero bytes)"
echo "Exiting..."
exit 1
fi
if [ ! -d ${dir} ]
then
echo "Invalid directory ${dir} entered"
echo "Exiting..."
exit 1
fi
cordir="./corrected"
prlogdir="./prlog"
if [ -d ${cordir} ]
then
echo "The corrected directory exist in the path, Please remove and run the tool again"
echo "Exiting..."
exit 1
else
mkdir ${cordir}
fi
if [ -d ${prlogdir} ]
then
echo "The prlog directory exist in the path, Please remove and run the tool again"
echo "Exiting..."
exit 1
else
mkdir ${prlogdir}
fi
errFile="$prlogdir/scr_err.rpt"
sucFile="$prlogdir/scr_suc.rpt"
Lines=`wc -l $file`
cntr=1
while [ $cntr -le $Lines ]
do
src=`head -$cntr $file|tail -1`
echo "$cntr. Processing $src...."
srcPath="${dir}/${src}"
if [ ! -s ${srcPath} ]
then
echo "Script file ${src} does not exist in the path given" >> ${errFile}
else
cp $srcPath $cordir/$src.tmp
srctemp="$cordir/$src.tmp"
srccor="$cordir/$src.corrected"
printcnt=`grep -ci "^[ ]*print" $srctemp`
if [ $printcnt -ne 0 ]
then
cat $srctemp|sed 's/^[ ]*[ ]*print[ ]*(/#print(/'|sed 's/^[ ]*[ ]*PRINT[ ]*(/#PRINT(/' > $srccor
mv $srccor $srctemp
fi
prreposcnt=`grep -ci "printrepos" $srctemp`
if [ $prreposcnt -ne 0 ]
then
cat $srctemp|sed 's/^.*urhk_b2k_printRepos.*/#Printrepos statement removed/'|sed 's/^.*urhk_B2k_PrintRepos.*/#Printrepos statement removed/'|sed 's/^.*urhk_B2k_printRepos.*/#Printrepos statement removed/'|sed 's/^.*urhk_b2k_PrintRepos.*/#Printrepos statement removed/' > $srccor
else
cp $srctemp $srccor
fi
echo "Script file $src correction is done" >> ${sucFile}
rm $srctemp
diff $srcPath $srccor >> $prlogdir/$src.diff.rpt
fi
cntr=`expr $cntr + 1`
done
echo "done"
I am completely new to shell scripting. Can anyone help me to modify this script to comment "urhk_b2k_printRepos" lines and also comment "TRACE ON" lines.

Bash-scripting. Check file-status

I've been handed an assignment which goes as follows;
I should write a program that checks a file and print out if one of the following happens:
File is created
file is modified
file is deleted
I've made a working program ( my noobish way):
bool=true
if [ -e "$1" ]
then
dato=$(date -r "$1" "+%s")
datony=$(date -r "$1" "+%s")
while [ "$bool" = true ]
do
echo "File exists!"
sleep $2
datony=$(date -r "$1" "+%s")
if [ "$dato" -ne "$datony" ]
then
bool=false
echo "File modified!"
fi
if [ ! -e "$1" ]; then
bool=false
echo "File erased"
fi
done
fi
if [ ! -e "$1" ]
then
while [ "$bool" = true ]
do
echo "File does not exist!"
sleep $2
if [ -e "$1" ]
then
bool=false
echo "File created!"
fi
done
fi
The problem now is that i should make a new script that should take multiple files and check their statuses using my existing script. I need som help with how i should use my script to do that.
If you want to continue using $1 for files and $2 for sleep time.
first, put sleep time in a variable
sleepTime=$2
Put all the code you already made in a function (or a program)
checkFile(){
bool=true
if [ -e "$1" ]
then
dato=$(date -r "$1" "+%s")
datony=$(date -r "$1" "+%s")
while [ "$bool" = true ]
do
echo "File exists!"
sleep $2
datony=$(date -r "$1" "+%s")
if [ "$dato" -ne "$datony" ]
then
bool=false
echo "File modified!"
fi
if [ ! -e "$1" ]; then
bool=false
echo "File erased"
fi
done
fi
if [ ! -e "$1" ]
then
while [ "$bool" = true ]
do
echo "File does not exist!"
sleep $2
if [ -e "$1" ]
then
bool=false
echo "File created!"
fi
done
fi
}
create another function to separate the files and call the other function on background.
func_splitFiles(){
while [ ! -z $1 ];
do
checkFile $1 $sleepTime &
shift;
done;
}
In the "main" program you just call the function to split files passing $1
func_splitFiles $1
You should call the program passing files between quotes.
program.sh "file1 file2 file3" 1

Need help in resolving a small error in unix shell scripting

I am having a problem with a unix shell script.
The script is for renaming the Files and directories which is having spaces with "-" recursively.
Example "Stack Overflow" to "Stack-Overflow"
This is running perfectly and working , But I get this wierd error which I don't know where it is coming.
I am getting the below error though (last line),
./script.sh[164]: [: Test.dat: unexpected operator/operand
I know it is coming some where in below funtions,
fix_dirs
fix_files
my_rename
but not sure where.
Could some one please help me in finding the error (Sorry for the long script :) )?.
#!/usr/bin/ksh
USAGE="$0 -f directory
$0 -d directory
$0 -d -f directory
-f rename files
-d rename directories
"
usage ()
{
print -u2 "$USAGE"
exit 1
}
pathname ()
{
print -- "${1%/*}"
}
basename ()
{
print -- "${1##*/}"
}
find_dirs ()
{
find "$1" -depth -type d -name '* *' -print
}
find_files ()
{
find "$1" -depth -type f -name '* *' -print
}
my_rename()
{
FROM_DIR="$1";
TO_DIR="$2";
if [ ! -w ${FROM_DIR##*/} ]
then
echo "Directory/file ${FROM_DIR##*/} Not Writable";
exit 1
fi
if [ -d "$TO_DIR" -o -f "TO_DIR" ]
then
echo "Target File or Directory already exists - $TO_DIR ";
exit 1
fi
mv "$FROM_DIR" "$TO_DIR"
STATUS=$?
if [ $STATUS -ne 0 ]
then
echo "Error in moving the file or directory";
echo "From directory : $FROM_DIR";
echo "To directory : $TO_DIR";
fi
}
fix_dirs ()
{
find_dirs "$1"|while read old_directory ; do
is_root_directory=`echo "old_directory" | grep -c "/"`;
if [[ $is_root_directory -ne 0 ]]
then
new_directory=$(pathname "$old_directory")/$(basename "$old_directory" | tr " " "_")
else
new_directory=$(echo "$old_directory" | tr " " "-")
fi
my_rename "${old_directory}" "${new_directory}"
done
}
fix_files ()
{
find_files "$1"|while read old_file ; do
new_file=$(pathname "$old_file")/$(basename "$old_file" | tr " " "-")
my_rename "${old_file}" "${new_file}"
done
}
WFILE=
WDIR=
DIR=
if [ "$#" -eq 0 ]
then
usage
fi
while [ $# -gt 0 ]
do
case $1 in
-d)
WDIR=1
;;
-f)
WFILE=1
;;
-*)
usage
;;
*)
if [ -d "$1" ]
then
DIR="$1"
else
print -u2 "$1 does not exist ..."
exit 1
fi
;;
esac
shift
done
if [ -z "$DIR" ]
then
echo "Please enter the directory";
exit 1
fi
if [ ${PWD} == "$DIR" ]
then
echo "Cannot perform rename on current directory";
exit 1
fi
if [ "$DIR" == "." -o "$DIR" == ".." ]
then
echo "cannot rename current or previous directory";
exit 1
fi
if [[ "$WDIR" == "" && "$WFILE" == "" ]] ; then
usage
exit 1
fi
if [ "$WDIR" -a "$WFILE" ]
then
fix_files "$DIR"
fix_dirs "$DIR"
elif [ "$WDIR" ]
then
fix_dirs "$DIR"
elif [ "$WFILE" ]
then
fix_files "$DIR"
fi
Running "ksh -n" on your example shows some possible problem on lines 70/71:
foo: warning: line 70: `...` obsolete, use $(...)
foo: warning: line 71: -ne within [[...]] obsolete, use ((...))
The relevant lines are
is_root_directory=`echo "old_directory" | grep -c "/"`;
if [[ $is_root_directory -ne 0 ]]
That was using a ksh93 on my Debian6, which likely is not the same version as the one you are using. However, you may find that making the suggested change to the second line will make your warning go away.
Thanks a lot for you information.
I tried bash similar to the ksh.
bash ./scriptname.sh
I corrected the errors. and below are the modified codes,
my_rename()
{
FROM_DIR="$1";
TO_DIR="$2";
if [ ! -w "${FROM_DIR##*/}" ]
then
echo "Directory/file ${FROM_DIR##*/} Not Writable";
exit 1
fi
if [ -d "$TO_DIR" -o -f "TO_DIR" ]
then
echo "Target File or Directory already exists - $TO_DIR ";
exit 1
fi
mv "$FROM_DIR" "$TO_DIR"
STATUS=$?
if [ $STATUS -ne 0 ]
then
echo "Error in moving the file or directory";
echo "From directory : $FROM_DIR";
echo "To directory : $TO_DIR";
fi
}
fix_dirs ()
{
find_dirs "$1"|while read old_directory ; do
is_root_directory=$(echo "$old_directory" | grep -c "/");
if [ $is_root_directory -ne 0 ]; then
new_directory=$(pathname "$old_directory")/$(basename "$old_directory" | tr " " "_")
else
new_directory=$(echo "$old_directory" | tr " " "-")
fi
my_rename "${old_directory}" "${new_directory}"
done
}

Check if passed argument is file or directory in Bash

I'm trying to write an extremely simple script in Ubuntu which would allow me to pass it either a filename or a directory, and be able to do something specific when it's a file, and something else when it's a directory. The problem I'm having is when the directory name, or probably files too, has spaces or other escapable characters are in the name.
Here's my basic code down below, and a couple tests.
#!/bin/bash
PASSED=$1
if [ -d "${PASSED}" ] ; then
echo "$PASSED is a directory";
else
if [ -f "${PASSED}" ]; then
echo "${PASSED} is a file";
else
echo "${PASSED} is not valid";
exit 1
fi
fi
And here's the output:
andy#server~ $ ./scripts/testmove.sh /home/andy/
/home/andy/ is a directory
andy#server~ $ ./scripts/testmove.sh /home/andy/blah.txt
/home/andy/blah.txt is a file
andy#server~ $ ./scripts/testmove.sh /home/andy/blah\ with\ a\ space.txt
/home/andy/blah with a space.txt is not valid
andy#server~ $ ./scripts/testmove.sh /home/andy\ with\ a\ space/
/home/andy with a space/ is not valid
All of those paths are valid, and exist.
That should work. I am not sure why it's failing. You're quoting your variables properly. What happens if you use this script with double [[ ]]?
if [[ -d $PASSED ]]; then
echo "$PASSED is a directory"
elif [[ -f $PASSED ]]; then
echo "$PASSED is a file"
else
echo "$PASSED is not valid"
exit 1
fi
Double square brackets is a bash extension to [ ]. It doesn't require variables to be quoted, not even if they contain spaces.
Also worth trying: -e to test if a path exists without testing what type of file it is.
At least write the code without the bushy tree:
#!/bin/bash
PASSED=$1
if [ -d "${PASSED}" ]
then echo "${PASSED} is a directory";
elif [ -f "${PASSED}" ]
then echo "${PASSED} is a file";
else echo "${PASSED} is not valid";
exit 1
fi
When I put that into a file "xx.sh" and create a file "xx sh", and run it, I get:
$ cp /dev/null "xx sh"
$ for file in . xx*; do sh "$file"; done
. is a directory
xx sh is a file
xx.sh is a file
$
Given that you are having problems, you should debug the script by adding:
ls -ld "${PASSED}"
This will show you what ls thinks about the names you pass the script.
Using -f and -d switches on /bin/test:
F_NAME="${1}"
if test -f "${F_NAME}"
then
echo "${F_NAME} is a file"
elif test -d "${F_NAME}"
then
echo "${F_NAME} is a directory"
else
echo "${F_NAME} is not valid"
fi
Using the "file" command may be useful for this:
#!/bin/bash
check_file(){
if [ -z "${1}" ] ;then
echo "Please input something"
return;
fi
f="${1}"
result="$(file $f)"
if [[ $result == *"cannot open"* ]] ;then
echo "NO FILE FOUND ($result) ";
elif [[ $result == *"directory"* ]] ;then
echo "DIRECTORY FOUND ($result) ";
else
echo "FILE FOUND ($result) ";
fi
}
check_file "${1}"
Output examples :
$ ./f.bash login
DIRECTORY FOUND (login: directory)
$ ./f.bash ldasdas
NO FILE FOUND (ldasdas: cannot open `ldasdas' (No such file or directory))
$ ./f.bash evil.php
FILE FOUND (evil.php: PHP script, ASCII text)
FYI: the answers above work but you can use -s to help in weird situations by checking for a valid file first:
#!/bin/bash
check_file(){
local file="${1}"
[[ -s "${file}" ]] || { echo "is not valid"; return; }
[[ -d "${file}" ]] && { echo "is a directory"; return; }
[[ -f "${file}" ]] && { echo "is a file"; return; }
}
check_file ${1}
Using stat
function delete_dir () {
type="$(stat --printf=%F "$1")"
if [ $? -ne 0 ]; then
echo "$1 directory does not exist. Nothing to delete."
elif [ "$type" == "regular file" ]; then
echo "$1 is a file, not a directory."
exit 1
elif [ "$type" == "directory" ]; then
echo "Deleting $1 directory."
rm -r "$1"
fi
}
function delete_file () {
type="$(stat --printf=%F "$1")"
if [ $? -ne 0 ]; then
echo "$1 file does not exist. Nothing to delete."
elif [ "$type" == "directory" ]; then
echo "$1 is a regular file, not a directory."
exit 1
elif [ "$type" == "regular file" ]; then
echo "Deleting $1 regular file."
rm "$1"
fi
}
https://linux.die.net/man/2/stat
https://en.m.wikipedia.org/wiki/Unix_file_types
A more elegant solution
echo "Enter the file name"
read x
if [ -f $x ]
then
echo "This is a regular file"
else
echo "This is a directory"
fi
Answer based on the title:
Check if passed argument is file or directory in Bash
This works also if the provided argument has a trailing slash .e.g. dirname/
die() { echo $* 1>&2; exit 1; }
# This is to remove the the slash at the end: dirName/ -> dirName
fileOrDir=$(basename "$1")
( [ -d "$fileOrDir" ] || [ -f "$fileOrDir" ] ) && die "file or directory $fileOrDir already exists"
Testing:
mkdir mydir
touch myfile
command dirName
# file or directory mydir already exists
command dirName/
# file or directory mydir already exists
command filename
# file or directory myfile already exists
#!/bin/bash
echo "Please Enter a file name :"
read filename
if test -f $filename
then
echo "this is a file"
else
echo "this is not a file"
fi
One liner
touch bob; test -d bob && echo 'dir' || (test -f bob && echo 'file')
result is true (0)(dir) or true (0)(file) or false (1)(neither)
This should work:
#!/bin/bash
echo "Enter your Path:"
read a
if [[ -d $a ]]; then
echo "$a is a Dir"
elif [[ -f $a ]]; then
echo "$a is the File"
else
echo "Invalid path"
fi

Resources