looking for some bash shell magic with globbing
I realize by default that when I execute a command like "xyz *", the shell expands the * and to disable that behavior I can do one of two things:
- quote the * like this: xyz '*' - turn off word expansion like this: set -f, before running my command I prefer the latter because expecting users to use quotes is a pain and it in fact works just fine. BUT... The trick is how to turn expansion back on after I execute xyz! I first tried an alias that did something like this: cmd='set -f; xyz, set +f' which works fine as long as xyz doesn't take any arguments, which it does! so then I thought I could turn off expansion in the alias and turn it back on from within xyz, which happens to be a perl script, something like: `set +f` but that would essentially start a new process and so the set would affect that process, not the one my perl script is running in. has anyone successfully done this sort of thing? I gotta believe there's a standard way to do it. -mark |
You can try a shell function:
Code:
function xyz() { |
Nope, I can't think of any way to do it cleanly. As you've discovered, aliases only work to replace the initial command name with the substituted string, and there's no way to arrange arguments in arbitrary order.
The usual way to set up such commands is with a function, but in this case, the globs would still have to be quoted in order to pass them to the function unexpanded first, thus defeating the whole purpose of it. (sorry colucix ;)) The only option I can suggest that even comes close is to put set +f in your PROMPT_COMMAND variable, and then it would be executed after every command execution. Of course that would mean you could never keep globbing unset for more than a single command. The final suggestion I could make is just to set up a simple command for quickly toggling the setting on and off, which you can run just before and after your xyz command: Code:
# "gt" stands for "glob toggle" PS: Please use [code][/code] tags around your code and data, to preserve formatting and to improve readability. Please do not use quote tags, colors, or other fancy formatting. |
Hold on, I just had an inspiration. A combination of alias and function just might do the trick.
Code:
|
I'm not sure I follow, but I think understand functionally what you're suggesting and it sounds promising. what is exactly is xyzfunc? a one line script? I'm not sure what it would consist of. who calls the xyzfunc function?
just to give a little perspective, I'm trying to build my own ls command, called sls, that does different sorts of things but still supports wild cards. so using your syntax if I build an alias like: alias sls='set -f; xyzfunc' what is the name of the file with xyzfunc in it and what exactly is in it? -mark |
Quote:
|
It seems to me this does what you want
Code:
set -f && ./t.sh * && set +f Code:
echo "P1 = $1" |
> set -f && ./t.sh * && set +f
That's not what I want to do. I want to pass $1 to my script. Sometimes it will be an * and sometimes not. But I get the general idea and hopefully can get it to do what I want. Thanks. -mark |
I keep going back and forth on this. One minute I think it's working and the next it's not. I think the problem is it's a different process resetting f and so that applies to the new process, not the original one. In other words, I don't think it works.
If someone could get this to work I'd love to see an example. -mark |
Quote:
The main problem you have here is that you need to alter the environment of the parent shell before the command line that executes the main script is parsed, and then again afterwards. The only way you can do this is with a command that is executed inside that shell itself; there's no way to do it from inside a script's sub-environment. This means you must use aliases and/or functions. And the only way I can think of to create a one-word command that will do exactly what you want in the main shell is to use both. Only an alias is capable of expanding a single command name into multiple commands before the rest of the line is parsed (meaning it's the only way you can turn off globbing). So we have to start with an alias. But as you know, it is then subsequently unable run another command after any arguments that follow it. So what we do is use the alias to launch a function instead, and use that function to run the subsequent commands in the required order. To break it down... Code:
alias xyz='set -f ; xyzfunc' Code:
xyz *.txt *.jpg Code:
set -f ; xyzfunc *.txt *.jpg Now we've also previously defined the function xyzfunc like this: Code:
xyzfunc() { command xyz "$@" ; set +f ; } "xyz" here is now the name of the actual script you want to run. The command keyword is added to ensure that it doesn't do any recursive processing of the alias name, and just runs the script directly. "$@" expands to a string of all the parameters passed to the function; here they become arguments to xyz. Since and "$@" is quoted (not to mention globbing is still off), they remain literal the whole time. So the function launches two commands in sequence: Code:
xyz *.txt *.jpg |
outstanding. I didn't realize there was a construct called a function in bash. guess I spend too much time living with perl ;)
-mark |
All times are GMT -5. The time now is 08:47 AM. |