Strings to integers?

Hi,

I'm totally new at this, so help will be appreciated.

I have a directory with a bunch of files in it. The files are named xinteger_yinteger_zinteger.vtk (eg, x3_y0_z-1.vtk). I want to read the filenames and then assign the integers to variables that I then can use in expressions. So, for x3_y0_z-1.vtk, I want to assign xvariable=3, yvariable=0, zvariable-1.

I assume that I have to use one command to assign a filename to a string and then something like printf to parse the string. But that's as far as I've gotten.

Help?

Thanks!

Let me see if I have got this right.

You want to extract the filename only and use the_values_ in the filename itself?

Do I take it you are not interested in the contents of the file itself?

Correct. I'm concerned only with the file names.

This solution is based on some assumptions (using parameter substitution):

#!/bin/bash

for file in *.vtk
do
        x="${file%%_*}"
        x="${x//[a-z]}"

        y="${file#*_}"
        y="${y%_*}"
        y="${y//[a-z]}"

        z="${file##*_}"
        z="${z%.*}"
        z="${z//[a-z]}"

        echo $x $y $z
done

Assuming that you're using a POSIX conforming shell (such as ksh or bash), the following seems to do what you want:

#!/bin/ksh
for file in x*_y*_z*.vtk
do
        printf "%s\n" "$file" | (
                IFS="xyz_." read x xvariable x yvariable x zvariable x
                printf "Processing file %s: x=%s, y=%s, z=%s\n" "$file" \
                        "$xvariable" "$yvariable" "$zvariable"
        )
done

When the above script is run in a directory containing the files:

problem
tester
x1_y2_z3.vtk
x3_y0_z-1.vtk

the output produced is:

Processing file x1_y2_z3.vtk: x=1, y=2, z=3
Processing file x3_y0_z-1.vtk: x=3, y=0, z=-1

This is longhand using OSX 10.7.5, default bash terminal...
Some assumptions have been made.

Last login: Sun Dec 22 22:12:49 on ttys000
AMIGA:barrywalker~> echo "junk stuff" > /tmp/x3_y0_z-1.vtk
AMIGA:barrywalker~> echo "junk stuff" > /tmp/x6_y0_z-5.vtk
AMIGA:barrywalker~> text=$(ls /tmp/*vtk)
AMIGA:barrywalker~> echo "$text"
/tmp/x3_y0_z-1.vtk
/tmp/x6_y0_z-5.vtk
AMIGA:barrywalker~> ifs_str="$IFS"
AMIGA:barrywalker~> IFS="$IFS/_."
AMIGA:barrywalker~> array=($text)
AMIGA:barrywalker~> x1="${array[2]:1:2}"
AMIGA:barrywalker~> y1="${array[3]:1:2}"
AMIGA:barrywalker~> z1="${array[4]:1:2}"
AMIGA:barrywalker~> echo "x=$x1, y=$y1, z=$z1"
x=3, y=0, z=-1
AMIGA:barrywalker~> x2="${array[7]:1:2}"
AMIGA:barrywalker~> y2="${array[8]:1:2}"
AMIGA:barrywalker~> z2="${array[9]:1:2}"
AMIGA:barrywalker~> echo "x=$x2, y=$y2, z=$z2"
x=6, y=0, z=-5
AMIGA:barrywalker~> IFS="$ifs_str"
AMIGA:barrywalker~> _

Great! You are in for learning the most interesting thing there is the world: shell programming in the Unix environment!

(Well, now that i jog my memory really hard, i have to admit there are a few other interesting activities too in life - but nothing is that rewarding, i promise. ;-)) )

You won't need "printf", but i appreciate you doing your own thinking. Lets go through it step by step:

First, we want to read in all the filenames in a directory. We do that in a loop:

#! /bin/ksh

typeset file=""

ls /path/to/your/dir |\
while read file ; do
     print - "we have found file ${file}"
done

exit 0

We define a variable "file" and in every pass of the loop this variable is set to a new value, cycling through all the file names in your directory. Once we are through it the loop ends and so does your script. The "print"-line is in there only for your edification: control if all the files you want to process are indeed shown and if every file you wanted to be left out is indeed left out. If this is not the case you might want to change your filemask, for instance:

ls /path/to/your/dir/*certain-extension |\
while read file ; do

otherwise you are ready to proceed: Now that we have the filename available we are ready to dissect it. In the shell this is done by so-called "variable expansion". You should indeed read a good book about shell programming which will cover this perhaps in a chapter of its own. Its a most often neglected art but one of the differences between the pros and the crowd. The reason: it might look awkward at first, but it is blazingly fast. You might need several lines, but these are executed faster by an order of magnitude than a single line calling some external utility.

Basically you can cut off patterns from a string from the front or the end. The first one is really easy:

file="x3_y0_z-1.vtk"
print - ${file%%.vtk}

You will see that the extension ".vtk" is removed. "%%" means: take the variables ("file") content and cut off from the end everything that matches the pattern (".vtk") and display what is left over. Let us put that into our script:

#! /bin/ksh

typeset file=""

ls /path/to/your/dir/*vtk |\
while read file ; do
     file="${file%%.vtk}"
     print - "we have now filename ${file}"
done

exit 0

Again, the "print"-statement serves no other purpose than to let you see what we have achieved so far. Now, the main work: let us first chop off "z". For this we use an "inverted %%", the "##". It removes a pattern beginning from the start of a string. Because we know that the value we want to know is at the end, following a "z", we can simply remove everything up to this letter:

file="x3_y0_z-1"
print - ${file##*_z}

The "*" means the same as in "ls -l *": any number of characters in any length. Let us put that into the script:

#! /bin/ksh

typeset file=""
typeset -i x=0
typeset -i y=0
typeset -i z=0

ls /path/to/your/dir/*vtk |\
while read file ; do
     file="${file%%.vtk}"
     z=${file##*_z}
     
     print - "Our x: $x  our y: $y    our z: $z"
done

exit 0

Likewise we are ready to get the other variables: first, we cut off the already extracted z-part, then we apply the same logic as before for the y-part:

file="x3_y0_z-1"
z=-1
file=${file%%z${z}}
print - "${file}"

Try these things on the command line. You can also play around with the patterns and the variable contents to get a feeling for this. Finally we put that into the script again:

#! /bin/ksh

typeset file=""
typeset -i x=0
typeset -i y=0
typeset -i z=0

ls /path/to/your/dir/*vtk |\
while read file ; do
     file="${file%%.vtk}"
     z=${file##*_z}
     file=${file%%z${z}}
     y=${file##*_y}
    
     print - "Our x: $x  our y: $y    our z: $z"
done

exit 0

I am sure by now you don't my explanations any more and you surely are eager to apply your newfound knowledge on the last part of the problem. Have fun with shell programming.

I hope that helps.

bakunin