ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
I tried to find the answer for this with searches here and everywhere else that I could, but it's hard to even know how to phrase the search to do that, so I'm asking here directly, where I can clarify to someone much more knowledgeable than I am.
What I'm trying to do is to check that each parameter in a Bash script is correct, including if each parameter is wildcarded, then halt the entire script if any of the parameters is incorrect.
The problem is that parameter expansion before I can even run the script is interfering with this.
For example, I start the script with these lines:
for x in $@ ; do
case $x in
*.jpg|*.mp4)
echo OKAY
;;
*)
echo NOT OKAY
exit
;;
esac
done
What I'm trying to do is to get it to stop the script entirely if even one of the parameters ($@) does not match the choices in the first case strings.
For example, if I use *.j?g *.mp? together as the parameters, it should continue with the rest of the script, but if *.jpg *.jp are the parameters, I need the script to detect the incorrect *,jp parameter and exit.
In fact, if I pass one of the parameters using a wildcard that I want to stop the script, it only stops if a file matching that file spec exists to match the wildcard and expand it.
Obviously, I need it to halt whether that file exists or not.
I've tried everything that I can think of, including "set -f" to turn off expansion, but the problem is that only works if I have "set -f" switched on before the script even starts, obviously because otherwise the parameters are expanded on the command line before the script executes.
I'm essentially in a chicken-and-the-egg situation with parameter string checking on this one.
My apologies if the way that I'm asking my question is overly verbose or poorly worded, but I'm still hoping that someone can help with the answer on this one.
EDIT: I found that I actually have no problem accomplishing what I want with this script if I execute it from the bash shell first, but I use TCSH as my regular shell, and that is when it fails.
I know that's unconventional for most people, but I started on TCSH nearly thirty years ago and find that more comfortable than bash for my login shell.
Is there something that can work around that?
To the best of my knowledge there's no way to tell whether arguments passed from the parent shell were the results of an expansion or not. There are the nullglob and failglob shell options, but they must already set in the parent shell.
It's just the way shell expansion and argument passing works on UNIX.
What folks normally do is check whether the file exists and is of the correct type before acting on it. Remember, file extensions are a microsoft thing. Though we tend to still use them in UNIXland, it's only by convention and they're not really significant.
Yes, a lot of questions. First of all, you need to decide if you want tcsh or bash, the syntax is different.
Next, the shell (terminal) will evaluate the command and will replace *.jpg and similar expressions, if possible (see shell expansion, failglob and others).
So in your case $@ will not contain *.jpg, but all the jpg files. Furthermore you ought to use shellcheck to check your script.
I guess you only need to check if the passed parameters are valid files, do not need to take care of shell expansion at all.
Additionally please use code blocks to post your scripts.
#!/bin/bash
for x in "$@"
do
case $x in
( *.j?g | *.mp? )
echo "OKAY"
;;
( * )
echo "NOT OKAY"
exit
;;
esac
done
The script arguments are evaluated+expanded already by the invoking shell unless protected by quoting or by using set -f or set noglob
The glob pattern in case-esac follows the same rules as the argument expansion, so here you might not see any difference if expansions occurred or not.
Last edited by MadeInGermany; 12-27-2023 at 10:23 AM.
#!/bin/bash
for x in "$@"
do
case $x in
( *.j?g | *.mp? )
echo "OKAY"
;;
( * )
echo "NOT OKAY"
exit
;;
esac
done
The script arguments are evaluated+expanded already by the invoking shell unless protected by quoting or by using set -f or set noglob
The glob pattern in case-esac follows the same rules as the argument expansion, so here you might not see any difference if expansions occurred or not.
The part about the shell evaluating/expanding the arguments isn't a problem if I run the script from within a bash shell.
The problem is that I use TCSH as my login shell,and it does the expansion/evaluation before the script starts, and I see no way to stop that before the script.
Can I assume that there's no temporary option from within TCSH that I can use on the way to running the Bash scrip that sidesteps this?
Yes, I know well that TCSH is a far less popular shell than Bash, but I'm much more comfortable using it for my login shell, with Bash for all of my scripts.
Thanks for the suggestions and information up to this point from everyone.
When you type in the command and hit enter it is already too late to examine the command line parameters unexpanded. At that point, with the enter key hit, the running shell (and it may be different from the script shell) expanded any globs.
You might want to rethink this, and instead examine the individual list entries that result and act on that basis.
I dug around a bit in the man page for TCSH, where I found information about the "noglob" variable.
I then found that simply doing "set noglob" on the command line immediately before running the script gives me exactly what I want, with the script stopping with any incorrect wildcard and operating normally with correct ones.
Thanks for the help everyone, and finding this answer could be useful for the few other TCSH users out there.
This is now going marked as unquestionably solved.
Just one more little comment that makes this solution now work much more easily:
I have several bash scripts that need to work on the same principle as the one that I mentioned, so I solved it with a simple alias that operates within a subshell, setting the "noglob" variable, running the script, which allows the "noglob" variable to automatically switch off at the conclusion of the alias.
The alias looks like this:
alias GAME_CAMERA '( set noglob ; GAME_CAMERA.sh \!:* )'
This is basically an alias wrapper for a Bash script, and it works perfectly after testing every way possible.
This might be useful to others in a similar situation of globbing causing problems with their own Bash scripts run from TCSH.
I guess basically the shell can do the globbing and you need to check only the result. There is no reason to do that by yourself instead of the shell. But anyway, if you wish you can do that.
This was the world of Windows, where each program handled this itself (instead of the shell).
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.