Checking for multiple files with bash script - bash

I have a bash file where I am currently using an if statement to check for two files existing before continuing with the rest.
if [[ -e $flchck ]] && [[ -e $flchck2 ]]; then
--do stuff here
else
--sends me an email telling me the files were not found.
My question is, is this the most efficient way to do this? If I need it to check more files, would I just keep adding && to include more.
What if I want it to tell me which file(s) was missing when it did this check.
Any guidance/direction on how to handle this would be greatly appreciated.

Typically one would use an array for this purpose. Assuming that your error-report-mailing code is encapsulated in a command named send_error_email, this may look like:
#!/usr/bin/env bash
files=( /path/to/file1 /path/to/file2 /path/to/file3 )
for file in "${files[#]}"; do
if ! [[ -e $file ]]; then
send_error_email "$file does not exist"
exit 1
fi
done
# do stuff here

Related

Bash Recursive Loop searching for file

Our assignment was just a conditional statement to say if a file exists or doesn't in the current directory. I already completed the primary objective but I am just trying to figure out how I could recurse using a loop and finding any other occurrences of the file name.
Currently, I am getting an infinite loop after finding the file in the first directory.
File exists and is located at /home/charlie/file.txt
File exists and is located at /home/charlie/file.txt
...
**Questions:
Would I need to have a nested for loop somewhere even though I am recursively calling the function?
Does using $pwd mess it up as I am trying to step into the directories?
Why is it printing twice as of now?**
#!/bin/bash
if [[ $# -eq 0 ]] ; then
echo 'Usage: findFile_new.sh [file name]'
exit 0
fi
exist="File exists and is located at "
function check() {
for file in $(pwd)/*
do
if [ -d "$file" ]; then
check $file $1
else
## Look for file
if [ -f "$1" ]; then
echo $exist$(pwd)/$1
fi
fi
done
}
check $1
Getting closer....
Why am i getting this as my output????
File exists and is located at
/home/charlie//#/*testFile.txt
File exists and is located at
/home/charlie//compareQuiz.sh/testFile.txt
File exists and is located at
/home/charlie//dir1/dir2/dir3/dir4//*testFile.txt
File exists and is located at
/home/charlie//dir1/dir2/file.txt/*testFile.txt
File exists and is located at
/home/charlie//dir1/dir2/testFile.txt/*testFile.txt
File exists and is located at
/home/charlie//findFile_new.sh/*testFile.txt
File exists and is located at
/home/charlie//testFile.txt/*testFile.txt
File exists and is located at
/home/charlie//testscript.sh/*testFile.txt
File exists and is located at
/home/charlie//~/*testFile.txt
#!/bin/bash
if [[ $# -eq 0 ]] ; then
echo 'Usage: findFile_new.sh [file name]'
exit 0
fi
exist="File exists and is located at "
echo $1 $2
function check() {
for file in $1/*
do
if [ -d "$file" ]; then
check $file $2
else
## Look for file
if [ -f "$2" ]; then
echo $exist$file
fi
fi
done
}
check $1 $2
Yes, you are almost there. A possible problem is the variable $file
will contain pathname to the file such as path/to/the/testFile.txt while
the variable $2 may contain only testFile.txt.
Would you please try the following:
#!/bin/bash
# usage: check path targetname
check() {
local file
for file in "$1"/*; do
if [[ -d $file ]]; then
check "$file" "$2"
elif [[ -f $file && ${file##*/} = $2 ]]; then
echo "found: $file"
fi
done
}
if (( $# != 2 )); then
echo "usage: $0 path name"
exit 0
fi
check "$1" "$2"
The expression ${file##*/} removes the pathname preceding the rightmost slash
inclusive and now you can compare it with $2.
Your search is not truly recursive and will eventually fall into an infinite loop.
Rolling your own Bash script that would cover every case for recursive search within a directory - can be tricky (permission handling and links come to mind...)
What you could do - is to use find which takes care of all recursive woes, and then extract the data you may need. The script (or single command really) would be find . -iname $1
find . (in this directory) -iname match this name and ignore case and $1 first arg value.
From the above you could grep to extract any data you may need.
I know this does not answer your question 1:1, but if you're just starting with Bash, I'd say you're better off using tools provided within Bash first, then trying rolling your own.
As your task was already accomplished and it's more of a general question, I figured I'd provide you with "what I would do". :)
Another point - when using $pwd - this being a bash reserved environment variable, it's better to use $PWD. It makes it simple to understand which env_vars are user declared and which are system reserved.
edit:
If you'd like to see a nice example of how this can be done, please checkout https://www.shellscript.sh/eg/directories/#traverse2.sh

Bash Scripting: I currently am supposed to have 500 files inside a directory, how can I stop a bash script if any files are missing?

I currently have a directory that is supposed to have 500 files. Each file is of the name form List.1.rds, ... List.500.rds. The way I can see which ones are missing is by the following code in bash:
for((i=1; i<=500; i++)); do name="List.${i}.rds"; [[ ! -e "$name" ]] && echo "missing $name"; done
If a file is missing, it returns the missing file name. However, I would like to go one step further and stop the entire script should any file be missing. Is there a way to do this? thanks.
It can be as simple as setting a flag when a file is missing:
miss=0
for ((i=1;i<=500;i++)); do
file=List.$i.rds
if [[ ! -e $file ]]; then
echo "Missing $file"
miss=1
fi
done
# exit if "miss" flag is 1
((miss)) && exit 1

Checking the input arguments to script to be empty failed in bash script

This a small bash program that is tasked with looking through a directory and counting how many files are in the directory. It's to ignore other directories and only count the files.
Below is my bash code, which seems to fail to count the files specifically in the directory, I say this because if I remove the if statement and just increment the counter the for loop continues to iterate and prints 4 in the counter (this is including directories though). With the if statement it prints this to the console.
folder1 has files
Looking at other questions I think the expression in my if statement is right and I am getting no compilation errors for syntax or another problems.
So I just simply dumbfounded as to why it is not counting the files.
#!/bin/bash
folder=$1
if [ $1 = empty ]; then
folder=empty
counter=0
echo $folder has $counter files
exit
fi
for d in $(ls $folder); do
if [[ -f $d ]]; then
let 'counter++'
fi
done
echo $folder has $counter files
Thank you.
Your entire script could be very well simplified as below with enhancements made. Never use output of ls programmatically. It should be used only in the command-line. The -z construct allows to you assert if the parameter following it is empty or non-empty.
For looping over files, use the default glob expansion provided by the shell. Note the && is a short-hand to do a action when the left-side of the operand returned a true condition, in a way short-hand equivalent of if <condition>; then do <action>; fi
#!/usr/bin/env bash
[ -z "$1" ] && { printf 'invalid argument passed\n' >&2 ; exit 1 ; }
shopt -s nullglob
for file in "$1"/*; do
[ -f "$file" ] && ((count++))
done
printf 'folder %s had %d files\n' "$1" "$count"

Bash + check for file exist with a path home ~

I haven't found anything to deal with this particular situation. Maybe there is a easy way that I'm overlooking instead of checking for a string to catch this scenario. When I check an input for existence of a file, if the input is ~/filecheck , this won't work. I get negative results while the file is in my home folder. Any suggestions for improvement to any part of the script I will definitely appreciate. I also have to use an input instead of a argument. Thanks for any help.
my test script
read -p "Enter: " input
echo $input
if [ -f $input ]; then
read -p "Do you REALLY want to delete this file?:" input2
if [[ $input2='y' || $input2 = 'Y' ]]
then
rm -f $input
elif [[ $input2='n' || $input2='N' ]]
then
exit
else
echo "Invaild Option"
exit
fi
else
echo Invaild Option!
exit
fi
Since you are entering input string as ~/filecheck shell doesn't expand tilde while using condition with -f in [ -f $input ]
You can use it this way but it is not recommended and potentially dangerous as arbitrary commands can be run by user:
if [[ -f $(bash -c "echo $input") ]]; then
echo "file exists"
fi
EDIT: As per the comments below to avoid risky bash -c you can use:
if [[ -f "${input/\~/$HOME}" ]]; then
echo "file exists"
fi
You can't have tilde expansion in this part of the program without using something based on eval—and you don't want to do that with user input. So, your poor-man solution will be to substitute any potential leading ~/ with the expansion of $HOME/. Here's the adaptation of your script in an arguably better style:
#!/bin/bash
read -e -p "Enter: " input
input=${input/#~\//$HOME/} # <--- this is the main idea of this answer (and it's rather poor)
echo "$input"
if [[ -f $input ]]; then
read -e -p "Do you REALLY want to delete this file? " input2
if [[ ${input2,,} = y ]]; then
rm -f -- "$input"
elif [[ ${input2,,} = n ]]; then
exit
else
echo "Invalid Option"
exit
fi
else
echo "Invalid Option!"
fi
exit
Now, out of curiosity, why are you spending time to make a wrapper around rm? you're making a clunky interface to an already existing program, without adding anything to it, only rendering it less powerful and less easy to use.
If all what you want it's to ask the user before deleting, you can use:
rm -i
This will give you appropriate error in the case file does not exist.

Reading a Directory and Verifying if it exists Bash

I have checked everywhere and tried many different "Solutions" on checking to see if the directory exists. Here's my code:
#!/bin/bash
echo -e "Where is the directory/file located?"
read $DIRECTORY
if [ -d "$DIRECTORY" ]; then
echo "Exists!"
else
echo "Does not exist!"
fi
What I am trying to do is have the user input a directory and for the script to check if it exists or not and return a result. This will ultimately tar/untar a directory. Regardless of whether the directory exists or not, it returns the answer "Does not exist!". (The input i'm trying is ~/Desktop, and from what I know that is 100% correct. Any concise answers are much appreciated :).
Your script can be refactored to this:
#!/bin/bash
read -p 'Where is the directory/file located?' dir
[[ -d "$dir" ]] && echo 'Exists!' || echo 'Does not exist!'
Basically use read var instead of read $var
Better not to use all caps variable names in BASH/shell
Use single quotes while using ! in BASH since it denotes a history event

Resources