How do I do this?
if [ -f town-*.swf ]
then
mkdir towns
fi
This checks if town-*.swf
exists, but I also need it to look for city-*.swf
among others, so I need something like this:
if [ -f town-*.swf, city-*.swf ]
then
mkdir towns
fi
How do I do this?
if [ -f town-*.swf ]
then
mkdir towns
fi
This checks if town-*.swf
exists, but I also need it to look for city-*.swf
among others, so I need something like this:
if [ -f town-*.swf, city-*.swf ]
then
mkdir towns
fi
POSIXly, you can use ls
if ls town-*.swf >/dev/null 2>&1 &&
ls city-*.swf >/dev/null 2>&1
then
mkdir towns
fi
or shorter if condition:
if ls town-*.swf city-*.swf >/dev/null 2>&1
even if your shell supports brace expansion:
if ls {town,city}-*.swf >/dev/null 2>&1
if stat -t city-*.swf >/dev/null 2>&1
then
if stat -t town-*.swf >/dev/null 2>&1
then
mkdir towns
fi
fi
As user uwe pointed out in the comments, my previous command would prevent the wild card from being expanded. However, this new version should work.
If you need it with a single if
loop, you could modify the script as,
if stat -t city-*.swf >/dev/null 2>&1 && stat -t town-*.swf >/dev/null 2>&1
then
mkdir towns
fi
If you need to specify an or condition instead of the and condition, you could replace &&
with ||
.
Testing
ls
city-1.swf city-2.swf city-3.swf city-4.swf city-5.swf sc.sh
town-1.swf town-2.swf town-3.swf town-4.swf town-5.swf
Now, I execute the script which is named as sc.sh
and then I could see that the towns directory is getting created successfully.
References
https://stackoverflow.com/questions/2937407/test-whether-a-glob-has-any-matches-in-bash
stat
works differently on different platforms. The -t
option does something completely different in FreeBSD and OSX than it does in Linux.
– ghoti
Oct 24 '14 at 21:24
In most cases command test ( [ )
offer operators -a
and -o
EXPR1 -a EXPR2
True if both expr1 AND expr2 are true.
EXPR1 -o EXPR2
True if either expr1 OR expr2 is true.
But in the case of possible multi-lines you should use command which can operate in the condition (for example ls
)
ls {town,city}-*.swf &>/dev/null && mkdir town
You can use the fact that globbing when can't to find the substitution remain the string as is (in the case with *
). So we just need to check is it somewhere in the line:
set -- {city,town}-*.swf
[[ ! "$*" =~ \* ]] && mkdir town
Or use case
(as offered in comments above)
case $(ls) in
*city-*.swf*town-*.swf*) mkdir town ;;
esac
find
was better. And you can always -exec sh -c 'script'
. In there you might kill find
and so only ever do one -exec
. (plus ls
has been done already...)
– mikeserv
Oct 25 '14 at 12:42
find
too but in the case we need to check two conditions the command string can be rather difficult
– Costas
Oct 25 '14 at 12:48
POSIX defines the -p
option to the pathchk
utility so...
-p
Instead of performing checks based on the underlying file system, write a diagnostic for each pathname operand that:
Is longer than {_POSIX_PATH_MAX} bytes (see Minimum Values in the Base Definitions volume of IEEE Std 1003.1-2001, Chapter 13, Headers, )
Contains any component longer than {_POSIX_NAME_MAX} bytes
Contains any character in any component that is not in the portable filename character set
If the filenames you are looking for should match only characters in the portable filename character set - which is comprised of ASCII letters and digits and ._-/
- then the following command will work as well as any without having to do any more stat()
calls than the shell does to glob them:
if pathchk -p town-*.swf city-*.swf
then mkdir towns
fi
Another way is to glob the pathname twice - once for an already known value and once also for the unknown. It the known value glob is not stripped then it is because the unknown value did not resolve.
Consider the following:
mkdir test
touch test/testfile1
echo tes[t]/test*1 tes[t]/test*2
test/testfile1 tes[t]/test*2
Here we know the test
path exists and so we can test for its resolution when attempting to match the unknown path's resolution.
For example, let's assume your current working directory is comprised entirely of pathnames that do not end with a ?
and there are no one-off paths that do either. This is not such a big assumption to make either - it can even be assured like:
cd /tmp/no_question_mark\? && {
$_handle_it || exit
}; ln -s "$PWD" /tmp/no_question_marks
cd /tmp/no_question_marks
That assumption made, you can then do something like:
set "${PWD%?}"?/town-*.swf "${PWD%?}"?/city-*.swf
case "$*" in (*\?/*) ! echo 'missed at least one...';;
(*) echo 'got em all!'; mkdir towns;;
esac
Here's a solution that's lower impact than running the external command ls
, as well as being more portable than a solution based on stat
(which differs from OS to OS).
#!/bin/bash
found=false
for _ in town-*.swf, city-*.swf do
found=true; break
done
if $found; then
echo "Yup!"
fi
The underscore is a throwaway variable. The for
loop is an easy way to expand your list of files, and the break
insures that you won't waste cycles looping through a long file list. The executables true
and false
can be found in /bin/
or /usr/bin/
, and could be replaced with bash builtins or functions if you would prefer that optimization.
Note that this also should work in a /bin/sh
. (At least, it did for me in a couple of other operating systems.)
case
can (and often should) be used for testing equality or matching, but how do you want to usecase
to check whether a file exists? – Uwe Oct 24 '14 at 16:57town-*.swf
andcity-*.swf
, or could there be several ones? – Uwe Oct 24 '14 at 17:03town-1.swf
andtown-2.swf
? (If it's impossible, there's an easy solution; if it's possible, you have to work harder.) – Uwe Oct 24 '14 at 17:14