Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

How to test for just one file

55 views
Skip to first unread message

Matt

unread,
Mar 2, 2003, 11:14:12 PM3/2/03
to
I have an sh script wherein I want to test to see if a directory has
text files named "msg.xxxx," where xxxx is a series of random letters.

The code looks something like this:

if [ -f msg.* ]
then tar -czf msgs.tar.gz msg.*
fi

I was getting an error like this: "[: too many arguments".

I think the asterisk in the test was being expanded to include all files
beginning with msg, and the test program only wants one argument.

So how do I test to see if ANY file with that prefix exists, without
passing the test program all of those files that do exist?

Thanks for your patience, I'm an amateur!

William Park

unread,
Mar 2, 2003, 11:37:11 PM3/2/03
to

ls msg.*

>
> Thanks for your patience, I'm an amateur!

--
William Park, Open Geometry Consulting, <openge...@yahoo.ca>
Linux solution for data management and processing.

John DuBois

unread,
Mar 3, 2003, 12:48:24 AM3/3/03
to
In article <matt7846-9E746C...@corp.supernews.com>,

set -- msg.*
if [ -f "$1" ] ...


John
--
John DuBois spc...@armory.com KC6QKZ/AE http://www.armory.com/~spcecdt/

Stephane CHAZELAS

unread,
Mar 3, 2003, 1:49:40 AM3/3/03
to
On 03 Mar 2003 05:48:24 GMT, John DuBois <spc...@deeptht.armory.com> wrote:
[...]

> set -- msg.*
> if [ -f "$1" ] ...

That probably solves OP's problem, but note that the first
msg.xxx may exist but not be a regular file (or a symlink to a
regular file). Strictly speaking, you would have to check for
all positional parameters, or use things like "ls -ld msg.* 2>
/dev/null | grep '^-' > /dev/null" (provided that file names
don't contain newlines).

With zsh:

[ -f msg.*(-.[1]^N) ]

--
Stéphane

laura fairhead

unread,
Mar 3, 2003, 4:13:51 AM3/3/03
to
On Sun, 02 Mar 2003 23:14:12 -0500, Matt <matt...@hotmail.com> wrote:

>I have an sh script wherein I want to test to see if a directory has
>text files named "msg.xxxx," where xxxx is a series of random letters.
>
>The code looks something like this:
>
> if [ -f msg.* ]
> then tar -czf msgs.tar.gz msg.*
> fi
>
>I was getting an error like this: "[: too many arguments".
>
>I think the asterisk in the test was being expanded to include all files
>beginning with msg, and the test program only wants one argument.

Yeah.

>
>So how do I test to see if ANY file with that prefix exists, without
>passing the test program all of those files that do exist?

>
>Thanks for your patience, I'm an amateur!

You can take only the first word from the expansion of
'msg.*' and test that;

if ( set msg.*; [ -f "$1" ] )


then
tar -czf msgs.tar.gz msg.*
fi

[ the 'set' is executed in a sub-shell to avoid messing around
with the main script positional parameters ]

That will execute the 'tar' if there is at least one file
msg.* and the first file in the expanded list is a regular file.

Since testing one file for being regular might be regarded
as good as nothing in this case, due to the fact that any
of the other files could be non-regular files (eg: directory,
device, ...) you may think that you could just test that
the first parameter in the expansion was not the string
'msg.*' but it is possible that you can have a file called
this name in UNIX so that test wouldn't be good enough.

You could, however, get rid of the use of the sub-shell
(probably the lost efficiency is nothing compared to the
'tar' command but this is just another way );

for file in msg.*
do
[ -f "$file" ] && tar -czf msgs.tar.gz msg.*
break
done

This time 'for' is used in order to get the first word
from the expansion 'msg.*'. That word is checked and
it will 'tar' if it is a file, whether or not it is
it always exits because of the 'break' after only the
one loop.

byefornow
laura


--
alt.fan.madonna |news, interviews, discussion, writings
|chat, exchange merchandise, meet fans....
|Get into the groove baby you've got to... check us out!

Alan Perry

unread,
Mar 3, 2003, 12:37:45 PM3/3/03
to
Octually, just run a for loop

for i in `ls msg.*`
do
tar -czf msgs.tar.gz $i
done

"William Park" <openge...@yahoo.ca> wrote in message
news:b3um5n$1pns9v$1...@ID-99293.news.dfncis.de...

Tapani Tarvainen

unread,
Mar 3, 2003, 12:47:42 PM3/3/03
to
"Alan Perry" <alan...@covad.net> writes:

> Octually, just run a for loop
>
> for i in `ls msg.*`

Why ls? Isn't that equivalent with

for i in msg.*

??

--
Tapani Tarvainen

David Thompson

unread,
Mar 3, 2003, 1:24:24 PM3/3/03
to
"Tapani Tarvainen" wrote

> "Alan Perry" <alan...@covad.net> writes:
>
> > Octually, just run a for loop
> >
> > for i in `ls msg.*`
>
> Why ls? Isn't that equivalent with
>
> for i in msg.*

One would wish so, but if no files matching the msg.*
pattern actually exist, then the for loop will assign
the string "msg.*" to $x and execute the loop once.

Ie, this loop,

for x in *.msg ; do
echo $x
done

is not the same as this loop,

for x in `ls *.msg 2> /dev/null` ; do
echo $x
done

in the case where no files match the pattern. The first
example prints this output,

msg.*

whereas the second prints nothing.

--
David Thompson
dat...@yahoo.com


David Thompson

unread,
Mar 3, 2003, 1:32:37 PM3/3/03
to

"David Thompson" <dat...@yahoo.com> wrote in message
news:s5N8a.299825$iG3.36771@sccrnsc02...

> "Tapani Tarvainen" wrote
> > "Alan Perry" <alan...@covad.net> writes:
> >
> > > Octually, just run a for loop
> > >
> > > for i in `ls msg.*`
> >
> > Why ls? Isn't that equivalent with
> >
> > for i in msg.*
>
> One would wish so, but if no files matching the msg.*
> pattern actually exist, then the for loop will assign
> the string "msg.*" to $x and execute the loop once.
>
> Ie, this loop,
>
> for x in *.msg ; do
> echo $x
> done
>
> is not the same as this loop,
>
> for x in `ls *.msg 2> /dev/null` ; do
> echo $x
> done
>
> in the case where no files match the pattern. The first
> example prints this output,
>
> msg.*

Er, (*blush*) I've mixed that up, above should be *.msg,
but the OP's example used msg.*, sorry about that, my
fingers weren't paying attention.

--
David Thompson
dat...@yahoo.com

Just Another User

unread,
Mar 3, 2003, 1:36:54 PM3/3/03
to

"Matt" <matt...@hotmail.com> wrote in message
news:matt7846-9E746C...@corp.supernews.com...

ls *.msg > /dev/null 2>&1 && tar ......
(choose redirection appropriate to your shell. Above suits ksh)


Stephane CHAZELAS

unread,
Mar 3, 2003, 1:59:22 PM3/3/03
to
On Mon, 03 Mar 2003 18:24:24 GMT, David Thompson <dat...@yahoo.com> wrote:
[...]

> One would wish so, but if no files matching the msg.*
> pattern actually exist, then the for loop will assign
> the string "msg.*" to $x and execute the loop once.
>
> Ie, this loop,
>
> for x in *.msg ; do
> echo $x
> done
>
> is not the same as this loop,
>
> for x in `ls *.msg 2> /dev/null` ; do
> echo $x
> done
[...]

The problem with the `ls` construct is that if file name contain
any IFS character, the list will be broken.

One way to avoid the problem without using ls is:

zsh: setopt nullglob (or add "(N)" to the pattern)
bash: shopt -s nullglob

other shells:

set -- *.msg *[.]msg
case $* in
"*.msg *[.]msg") # no match found
;;
*)
for x in *.msg; do ...; done;;
esac

--
Stéphane

laura fairhead

unread,
Mar 3, 2003, 8:01:04 PM3/3/03
to
On 03 Mar 2003 18:59:22 GMT, Stephane CHAZELAS <stephane...@yahoo.fr>
wrote:

Like the idea :) I was wondering if you could do this
this morning, seems I don't have to wonder anymore...
Anyway, how about a simplification;

set -- *[.]msg
case $1 in


"*[.]msg") # no match found
;;

*) for x ; do ...; done;;
esac

Maybe it makes no difference, but could save a few directory
re-reads

>
>--
>Stéphane

bestwishes

Stephane CHAZELAS

unread,
Mar 4, 2003, 3:27:49 AM3/4/03
to
On Tue, 04 Mar 2003 01:01:04 GMT, laura fairhead <LoveMrs...@madonnaweb.com> wrote:
[...]

> set -- *[.]msg
> case $1 in
> "*[.]msg") # no match found
> ;;
> *) for x ; do ...; done;;
> esac
>
> Maybe it makes no difference, but could save a few directory
[...]

Right you are. In that particular case, it's enough. I was
actually reusing a construct I had imagined few hours earlier to
test wether a directory is empty or not (or contains only dot
files or is not readable...)

set x * ?*
case "$# $1 $2" in
"3 * ?*") # dir empty
;;
*) # not empty
;;
esac

--
Stéphane

Kevin Rodgers

unread,
Mar 4, 2003, 6:59:39 PM3/4/03
to
David Thompson wrote:

> "Tapani Tarvainen" wrote
>
>>"Alan Perry" <alan...@covad.net> writes:
>>
>>
>>>Octually, just run a for loop
>>>
>>>for i in `ls msg.*`
>>>
>>Why ls? Isn't that equivalent with
>>
>>for i in msg.*
>>
>
> One would wish so, but if no files matching the msg.*
> pattern actually exist, then the for loop will assign
> the string "msg.*" to $x and execute the loop once.
>
> Ie, this loop,
>
> for x in *.msg ; do
> echo $x
> done
>
> is not the same as this loop,
>
> for x in `ls *.msg 2> /dev/null` ; do
> echo $x
> done

Which is why the idiomatic usage is

for x in *.msg; do

[ -f "$x" ] || continue
# your code here
done

--
<a href="mailto:&lt;kevin.rodgers&#64;ihs.com&gt;">Kevin Rodgers</a>

laura fairhead

unread,
Mar 5, 2003, 2:04:08 AM3/5/03
to
On 04 Mar 2003 08:27:49 GMT, Stephane CHAZELAS <stephane...@yahoo.fr>
wrote:

>On Tue, 04 Mar 2003 01:01:04 GMT, laura fairhead <LoveMrs...@madonnaweb.com> wrote:

How about this to check for any files except '.' and '..';

set x * [*] .[!.]* '.[!.]'[*] .[.]?*
case $* in
"x * [*] .[!.]* .[!.][*] .[.]?*") # no files
;;
*) # files found
;;
esac

This is ny attempt at a proof (not satsified with it yet somehow);

There are 5 SPACE, this means that no SPACE could be added
by a filename (and they can't be taken away) so therefore
each filename is deliminated by a SPACE character, then
working right to left through the matching result string;

1 2 3 4 5
set x * [*] .[!.]* '.[!.]'[*] .[.]?*


RESULT STRING
v

.[.]?* (5) This implies that no file matching ..?* exists

.[!.][*] (4) This implies that no file called ".[!.]*" exists

.[!.]* (3) This implies no file matching .[!.]* exists
(because of the previous, no file ".[!.]*" exist)

So now there are no .* files except '.' and '..'

[*] (2) This implies no file called "*" exists

* (1) This implies (because not file "*") that no file matching *
exists

Hence, implies no files exist except '.' and '..'

This is one-way because result => no files

The other way around (no files => result) is just trivial
#


Not yet completely happy with this (it's the wrong time in the
morning, haha) but it seems okay generally,...

For a challenge get it down to 4 filename patterns only !

So then we have a test for 'any non-hidden files' in the current
directory and also 'any files' in the current. If all this could be
made to work on an arbitrary directory I would say it could even
go into the FAQ.

:-)

>
>--
>Stéphane


buenosdias

Stephane CHAZELAS

unread,
Mar 5, 2003, 3:38:00 AM3/5/03
to
On Wed, 05 Mar 2003 07:04:08 GMT, laura fairhead <LoveMrs...@madonnaweb.com> wrote:
[...]
> set x * [*] .[!.]* '.[!.]'[*] .[.]?*

Bright, as usual! The [*] idea is far better as my ?* that
duplicates the file list.

[...]


> For a challenge get it down to 4 filename patterns only !

Easy ;)

IFS=" " # to ensure "$*" is space separated
set x * [*] .* .[*]
case $* in
"x * [*] . .. .[*]"|\
"x * [*] . .[*]"|\
"x * [*] .. .[*]"|\
"x * [*] .* .[*]") ...
*) ...
esac

But I much prefer yours ;)


--
Stéphane

0 new messages