Mailinglist Archive: opensuse (2740 mails)

< Previous Next >
Re: [opensuse] bash - handling expansion of parameters on the command line?
  • From: David Haller <opensuse@xxxxxxxxxx>
  • Date: Tue, 2 Dec 2008 06:24:11 +0100
  • Message-id: <20081202052411.GB6419@xxxxxxxxxxxxxxxxxx>
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@xxxxxxxxxxxx
For additional commands, e-mail: opensuse+help@xxxxxxxxxxxx

< Previous Next >
References