Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations biv343 on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

bash shell - filename string question

Status
Not open for further replies.

chz013

Programmer
Jan 5, 2003
73
US
Hi
i have filenames in the following file test.txt
abc_0000
abc_0030
abc_0100
xyz_000
xyz_0030
xyz_0100
my_own_test

in my directory /tmp

How do I write a unix script that reads each
of these names in the listing test.txt
and only process files whose names ends with
0000, 0030, 0100, ....every 30 interval
and at the same time, disregard
my_own_test listing ?

Appreciate any help.

I tried

while read my_file; do

if [ ${my_file##*_} != [0-9] ]
then
echo "Not correct file!"
else
echo "correct file $my_file..."
fi

done < test.txt


 
Even if I change the condition

if [ ${stat_file##*_} != [0-9]\{4} ]

I still get my output as
:
:
Not correct file!
Not correct file!
Not correct file!
Not correct file!
Not correct file!
Not correct file!
Not correct file!
:
:
 
#!/bin/ksh

while read myFile
do

if [[ &quot;${myFile##*_}&quot; != @([0-9][0-9]*) ]] ; then
echo &quot;Not correct file!&quot;
else
echo &quot;correct file $myFile...&quot;
fi
done < num.txt


vlad
+----------------------------+
| #include<disclaimer.h> |
+----------------------------+
 
Vlad
You're a guru. Didnt expect to see u in unix scripting
forum too.

What does
@([0-9][0-9]*
really mean in the condition
[[ &quot;${myFile##*_}&quot; != @([0-9][0-9]*) ]]

I like to understand this.


 
from 'man ksh' [File Name Generation]:

?(pattern-list)
Optionally matches any one of the given patterns.

*(pattern-list)
Matches zero or more occurrences of the given pat-
terns.

+(pattern-list)
Matches one or more occurrences of the given pat-
terns.

@(pattern-list)
Matches exactly one of the given patterns.

!(pattern-list)
Matches anything, except one of the given pat-
terns.


vlad
+----------------------------+
| #include<disclaimer.h> |
+----------------------------+
 
Vlad

I get error

syntax error near unexpected token `[[&quot;${stat_file##*_}&quot;!=@([0-9][0-9]*)'
`if [[&quot;${stat_file##*_}&quot;!=@([0-9][0-9]*)]];'

my code
=======

while read stat_file; do

if [[&quot;${stat_file##*_}&quot;!=@([0-9][0-9]*)]];
then
echo &quot;Not correct file!&quot;
else
echo &quot;correct file $myFile...&quot;
fi

done < changed_date_files_listing


I even tried a variation like
if [[&quot;${stat_file##*_}&quot;!=@([0-9][0-9][0-9][0-9])]];

I still get the same error


why did I do wrong ?
is this something to do with bash version ?
how do I find out what bash version I have ?
 
there gotta be :
1. space after '[[' and before ']]'
2. spaces surrounding '!='
3. you don't need ';' if 'then' is NOT on the same line


vlad
+----------------------------+
| #include<disclaimer.h> |
+----------------------------+
 
I still get syntaz error:

./xfile.sh: line 215: syntax error in conditional expression
./xfile.sh: line 215: syntax error near unexpected token `@(['
./xfile.sh: line 215: `if [[ &quot;${stat_file##*_}&quot; != @([0-9][0-9][0-9][0-9]) ]] '



if [[ &quot;${stat_file##*_}&quot; != @([0-9][0-9][0-9][0-9]) ]]
then
 
ooops, I didn't notice Subject line of this post - you're using bash?

My example was for Korn. I'm not quite sure how to do the same in bash - probably using 'expr'].

Pls let me know if you really are using bash.

vlad
+----------------------------+
| #include<disclaimer.h> |
+----------------------------+
 
if in bash:

#!/bin/bash

while read myFile
do

if [[ $(expr &quot;${myFile##*_}&quot; : '.*[^0-9].*') -ne 0 ]] ; then
echo &quot;Not correct file [${myFile}]!&quot;
else
echo &quot;correct file [${myFile}]...&quot;
fi
done < num.txt


vlad
+----------------------------+
| #include<disclaimer.h> |
+----------------------------+
 
Vlad
Could you help explain this expression to me ?
I dont quite understand the parts in this if condition
here.

if [[ $(expr &quot;${myFile##*_}&quot; : '.*[^0-9].*') -ne 0 ]]

I didnt know expr is a keyword in bash.

Appreciate it.
 
from 'man expr':

----------------------------------------------------------
expr : expr
The matching operator : (colon) compares the first
argument with the second argument, which must be
an internationalized basic regular expression
(BRE); see regex(5) and NOTES. Normally, the
/usr/bin/expr matching operator returns the number
of bytes matched and the /usr/xpg4/bin/expr match-
ing operator returns the number of characters
matched (0 on failure). If the second argument
contains at least one BRE sub-expression
[\(...\)], the matching operator returns the
string corresponding to \1.

-----------------------------------------------------------

In your case:
if [[ $(expr &quot;${myFile##*_}&quot; : '.*[^0-9].*') -ne 0 ]]

${myFile##*_} - trims everything OFF up to a '_'

'expr' returns the number of bytes/chars matched of its TWO 'match' expressions. In your case you have expressions for myFile->[abc_0023]: '0023' and '.*[^0-9].*'

The second expression is a regex that says:
anything ('.*') followed by
anything BUT a number (^0-9) folowed by
anything ('.*')

What you're saying in essense here is: do I have string with NON-numeric characters in it.

When 'expr' gets evaluated and if it find as match of its 2 args (meaning there WERE some NON-numeric chars) it returns the number of chars/bytes matched which would be NON-ZERO. That's your 'then' branch of the 'fi'.

if all the chars WERE numeric the 'expr' would matching NOTHING from the SECOND expression and would return 'ZERO' - that's your 'else' branch of the 'if'.

Hope it's helpful.



vlad
+----------------------------+
| #include<disclaimer.h> |
+----------------------------+
 
Vlad
Suppose I have a filename
head_middle_abc_0000

how do I remove
head_middle_
and
_0000
from head_middle_abc_0000
so that I should only check for &quot;abc&quot; in my if condition.

I use
if [ ${file%_*} = abc ]; then
but this removes _0000 but not head_middle_


 
well.........

if [ &quot;$(echo ${file}| nawk -F'_' '{print $(NF-1)}')&quot; == &quot;abc&quot; ]

vlad
+----------------------------+
| #include<disclaimer.h> |
+----------------------------+
 
Does that mean I have to include

/usr/xpg4/bin/awk -f at the top of my shell script,
say

#!/usr/bin/bash
#!/usr/xpg4/bin/awk -f

in order to use awk

?
 
no, it does NOT.
Just specify your shell interpreter as you do now:

#!/usr/bin/bash

And for the 'if' condition, specify what's been suggested above:

if [ &quot;$(echo ${file}| nawk -F'_' '{print $(NF-1)}')&quot; == &quot;abc&quot; ]

NOTE: if you're NOT on Solaris, specify your flavor of 'awk' instead of Solaris's &quot;nawk&quot;.

vlad
+----------------------------+
| #include<disclaimer.h> |
+----------------------------+
 
Using the if condition you suggested,
I got
NF-1: command not found

Is there a way to remove substring one at a time ?
I'm surprised that

short_filename=&quot;${MyFile#middle_}&quot;
doesnt produce

head_abc_0000

Any suggestions ?
 
this is a sample script. You can use either one of 2 'if'-s

#!/bin/bash

file='head_middle_abc_0000'

#if [ &quot;$(echo ${file}| nawk -F'_' '{print $(NF-1)}')&quot; == &quot;abc&quot; ] ; then
if [ &quot;$(expr ${file} : '.*_abc_[0-9][0-9]*$')&quot; -ne 0 ] ; then
echo 'YES'
else
echo 'NO'
fi;


vlad
+----------------------------+
| #include<disclaimer.h> |
+----------------------------+
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top