How to exit a shell script if targeted file doesn't exist
You can check for file existence with something like:
if [[ -f x.txt ]] ; then echo file exists.fi
To exit if it doesn't, something like this would suffice:
if [[ ! -f x.txt ]] ; then echo 'File "x.txt" is not there, aborting.' exitfi
The -f <file>
is only one of the many conditional expressions you can use. If you look at the bash
man-page under CONDITIONAL EXPRESSIONS
, you'll see a whole host of them.
If (as stated in a question update) you wish to check if a wildcard results in files, you can simply expand it, throwing away the errors. If there are none, you'll end up with an empty string which can be detected with -z
:
if [[ -z "$(ls -1 */*.txt 2>/dev/null | grep ab1)" ]] ; then echo 'There are no "*/*.txt" files.' exitfi
Note that I've used -1
to force one file per line even though Linux ls
does that by default if the output device is not a terminal (from memory). That's just in case you try this on a machine that doesn't force one per line in that case.
Keep in mind however that, if you have spaces in your filenames, using ls
and then awk
to extract column 1 is not going to work too well. For example, the file abc ab1.txt
will result in the extraction of only the abc
bit.
Using find
with -print0
, combined with xargs
with -0
is the usual way to properly process files which may have "special" characters in them. There are many other options you can give to find
to ensure only the files required are processed, such as -maxdepth
to limit how far down the directory tree you go, and -name
to properly filter file names.
However, if you know that you will never have these types of files, it's probably okay to use the ls
solution, just make sure you're comfortable with its shortcomings.
Use test
A quick and short way of testing for existence:
test -e $FILENAME || exit
You can chain it by doing:
test -e $FILENAME && something | something-else
In which case something
and something-else
will only execute if the file exists.
For example:
➤ test -e ~/.bashrc && echo True || echo FalseTrue➤ test -e ./exists-not && echo True || echo FalseFalse
Aside: Note that [
is an alias for test
. The semantics of [[
are defined by bash and can be found on the bash manpage
However...
...you are probably better off using find
to get your files:
find ./ -maxdepth 2 -name "*ab1*.txt" -exec do-something-to-filename '{}' \;
As the output of ls
can not be reliably parsed. This will also only execute the command do-something-to-filename
if the filename exist, which is what I think you are trying to do.
{}
will be replaced by the filename for each invocation of do-something-to-filename
.
find ... -exec ...
or find ... -print0 | xargs -0 ...
is generally fine, but you can do it directly with a glob using bash's nullglob
option:
bash-3.2$ echo *foo*foobash-3.2$ shopt -s nullglobbash-3.2$ echo *foobash-3.2$
Depending on the rest of your script, you may or may not want to re-unset that with shopt -u nullglob
.