[opensuse] bash - handling expansion of parameters on the command line?
Bash wizards: I have run across another quandary. I am trying to get a filespec from the command line like: ./scriptname file1* and file name expansion occurs before I can assign the filespec to a variable. I want to be able to grab the 'file1*' filespec without having to require that it be enclosed in single quotes (./scriptname 'file1*'). I'm using the filespec like: FILESPEC=$1 NEWNAME=$2 for i in $(ls ${FILESPEC}); do echo -n "moving $i --> ${NEWNAME}.${i##*.}" if mv $i ${NEWNAME}.${i##*.}; then echo ".........Success" else echo ".........Failed" fi done Can I do it, or do I have to look at handling the expanded command line in another way like an array or something? The easiest way would probably be to swap NEWNAME to $1 and then do $2 until I run out of parameters, but that would defeat my preference of the command line being ./rename what to-what. What is the best way to skin this cat? (I've also learned that the expression can be 'wash that pig' in some parts as well) Thanks. -- David C. Rankin, J.D.,P.E. | openSoftware und SystemEntwicklung Rankin Law Firm, PLLC | Countdown for openSuSE 11.1 www.rankinlawfirm.com | http://counter.opensuse.org/11.1/small -- To unsubscribe, e-mail: opensuse+unsubscribe@opensuse.org For additional commands, e-mail: opensuse+help@opensuse.org
On Monday 01 December 2008 18:25, David C. Rankin wrote:
Bash wizards:
I have run across another quandary. I am trying to get a filespec from the command line like:
./scriptname file1*
and file name expansion occurs before I can assign the filespec to a variable. I want to be able to grab the 'file1*' filespec without having to require that it be enclosed in single quotes (./scriptname 'file1*'). I'm using the filespec like:
In limited circumstances you can, but I'm guessing they're not the ones you want. The only option you have in BASH is whether a wild-card that does _not_ match any files is treated as an error or passed unaltered. I prefer the latter, 'cause then you can do things like this: % egrep -Rl --include=*.java pattern files-and-dirs without quoting the argument and not get an error (and pretty much always count on that wildcard _not_ matching, which is of course what I want). This is probably a pretty good analog for your case. Egrep itself (as it Recursively traverses the directories given) will look at only those files that match one of the --include= patterns (and does not match one of the --exclude= patterns). However, if you want a pattern that _does_ match to still be passed unaltered, you're out of luck. There's nothing corresponding to control over argument expansion in BASH other than quoting the arguments. However, if you're willing to do something along these lines (as in the aforementioned egrep example or as dd does with arg=value format), then you've got something to work with.
... What is the best way to skin this cat? ...
The preferred colloquialism is "skin that rat."
Thanks.
-- David C. Rankin
Randall Schulz -- To unsubscribe, e-mail: opensuse+unsubscribe@opensuse.org For additional commands, e-mail: opensuse+help@opensuse.org
However, if you want a pattern that _does_ match to still be passed unaltered, you're out of luck. There's nothing corresponding to control over argument expansion in BASH other than quoting the arguments.
No, there is also set -f And I would not suggest pattern-won't-match tricks as a way to do things. It's a little gimmick you discovered you can use in some cases, which is fine, because when it fails, it doesn't hurt you because you are an experienced enough user to recognize what happened. But it's not actually a robust procedure and isn't a smart thing to suggest to anyone who even had to ask the original question. We don't know what "filespec" is, and so we shouldn't tell him that "file*" will pass in as it is as long as there is no "file*" in the current directory. That will just waste everyones time when someday there IS a file* in the directory, or he goes and tells the girls in his office "here, use it like this..." and they go and try to use the program without all this in depth familiarity with how the shell works and they type in path/to/somedir/file* because he didn't realise he needed to tell them not to, and there are file* in there. -- Brian K. White brian@aljex.com http://www.myspace.com/KEYofR +++++[>+++[>+++++>+++++++<<-]<-]>>+.>.+++++.+++++++.-.[>+<---]>++. filePro BBx Linux SCO FreeBSD #callahans Satriani Filk! -- To unsubscribe, e-mail: opensuse+unsubscribe@opensuse.org For additional commands, e-mail: opensuse+help@opensuse.org
Hello, On Mon, 01 Dec 2008, David C. Rankin wrote:
Bash wizards:
I have run across another quandary. I am trying to get a filespec from the command line like:
./scriptname file1*
and file name expansion occurs before I can assign the filespec to a variable.
You can't. But (see below).
I want to be able to grab the 'file1*' filespec without having to require that it be enclosed in single quotes (./scriptname 'file1*').
You MUST use single or double quotes around the pattern or escape the wildcard characters, if you want to pass the pattern to your script. I.e. one of: ./script 'file1*' ./script "file1*" ./script file1\*
I'm using the filespec like:
FILESPEC=$1
*BLAM* Missing double quotes.
NEWNAME=$2
*BLAM* Missing double quotes.
for i in $(ls ${FILESPEC}); do
*BLAM* Not missing quotes, but it'll bite you _badly_ anyway, for any filename containg special characters (like whitespace and a bunch of others). DO NOT EVER USE THAT.
echo -n "moving $i --> ${NEWNAME}.${i##*.}"
ok.
if mv $i ${NEWNAME}.${i##*.}; then
*BLAM* Missing double quotes. Twice! [..]
Can I do it, or do I have to look at handling the expanded command line in another way like an array or something?
Why would you want this? You would just pass the pattern back to the (sub-)shell (and on to ls, which'll bite you anyway) and then the shell has to expand it anyway.
The easiest way would probably be to swap NEWNAME to $1 and then do $2 until I run out of parameters, but that would defeat my preference of the command line being ./rename what to-what. What is the best way to skin this cat? (I've also learned that the expression can be 'wash that pig' in some parts as well)
The easiest way is: mmv 'file1*' 'newname#1' (with '-v' if you like) or use krename. But generally for "looping over files", you can do something like: ==== UNTESTED! ==== #!/bin/bash newname="$1"; ## get base for target filename, as first argument shift; ## get rid of it (pop it from the argument list) ## loop over the remaining arguments, i.e. the file list, possibly ## generated by the shell from the pattern for name; do ## == implicit: for name in "$@"; do ## let the shell and/or find + xargs ## take care of what names you get to ## see. target="${newname}.${name##*.}" mv -i "$name" "$target" ## do NOT use such a 'mv' in a script ## without -i, EVER! Unless you ## implement a check for and handle an ## existing target yourself (which is ## why I use 'target' here at all), or ## you like to shoot yourself in the ## foot with a bazooka and lose data. done ==== Call it as: ./script newname pattern* If you want verbose output, just use 'mv -i -v ...'. BTW: you realize, that you'll get collisions for any 2 files matched by the pattern, which have the same extension (after the last '.')? To remedy this, you'll have to construct "target" differently. Also, you could implement verbosity and target (newname) as options, but that (parsing options) is a bit out of scope right now. Any questions? HTH, -dnh PS: sorry if I sound a bit harsh ... -- If ignorance is bliss, why aren't there more happy people? -- To unsubscribe, e-mail: opensuse+unsubscribe@opensuse.org For additional commands, e-mail: opensuse+help@opensuse.org
----- Original Message -----
From: "David C. Rankin"
Bash wizards:
I have run across another quandary. I am trying to get a filespec from the command line like:
./scriptname file1*
You need to say ./scriptname 'file1*'
and file name expansion occurs before I can assign the filespec to a variable. I want to be able to grab the 'file1*' filespec without having to require that it be enclosed in single quotes (./scriptname 'file1*'). I'm using the filespec
Sorry, not an option. The only way you can get the litteral string "file1*" passed is to prevent the interactive shell from expanding it before-hand. The only ways to do this are: ./scriptname 'file1*' or ./scriptname file1\* or set -f ./scriptname file1* This shouldn't be viewed as a limitation or hardship, but rather as an ability or a feature. The ability to be precise. Globbing is a very powerful and useful feature, and so it's active by default. But sometimes in some rare and special cases you don't want the globbing to occure, and so another feature is the ability to suspend the globbing from happening, and since no single way of doing something is always convenient, there is even at least the 3 different methods above to suspend the globbing. In other words, I think it's a mistake to even try or want to avoid saying program 'litteral' That is the way the entire system works and as a unix shell user it should just be a natural part of the interface for you. You still need to use the same quoting and escaping syntax with every other program anyways, which means you still need know the times & places when globbing will happen and the times & places when you don't want it to happen. If you are trying to make a program that other users will use who are not necessarily unix users and you don't want them to require them to be this savvy, you could make the script interactive. Then they would type in the filespec into a read command, and you can put a set -f in the script before the read, then they wouldn't have to do any special quoting. Or you could make a seperate xterm/gnome-terminal/etc desktop icon that launches bash with -f so globbing is disabled for that window. -- Brian K. White brian@aljex.com http://www.myspace.com/KEYofR +++++[>+++[>+++++>+++++++<<-]<-]>>+.>.+++++.+++++++.-.[>+<---]>++. filePro BBx Linux SCO FreeBSD #callahans Satriani Filk! -- To unsubscribe, e-mail: opensuse+unsubscribe@opensuse.org For additional commands, e-mail: opensuse+help@opensuse.org
On Tuesday 02 December 2008 03:25:44 David C. Rankin wrote:
Bash wizards:
I have run across another quandary. I am trying to get a filespec from the command line like:
./scriptname file1*
and file name expansion occurs before I can assign the filespec to a variable. I want to be able to grab the 'file1*' filespec without having to require that it be enclosed in single quotes (./scriptname 'file1*').
Others have replied with how you should be doing it, so I'll just add how you can disable globbing (the term for matching wild cards with file names) set -f or set -o noglob on This will disable all globbing, so file1* will be sent as is to your program. You can turn it back on with either set +f or set -o noglob off Anders -- To unsubscribe, e-mail: opensuse+unsubscribe@opensuse.org For additional commands, e-mail: opensuse+help@opensuse.org
participants (5)
-
Anders Johansson
-
Brian K. White
-
David C. Rankin
-
David Haller
-
Randall R Schulz