LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   shell; number of elements in array (https://www.linuxquestions.org/questions/programming-9/shell%3B-number-of-elements-in-array-4175415832/)

Wim Sturkenboom 07-10-2012 01:41 AM

shell; number of elements in array
 
I'm busy with a file rename script. A typical filename that needs renaming consists of two parts (both variable length) separated by '@S' (e.g. 'wim@S1.mpg'); the separator must be changed to '@' so the resulting filename is 'wim@1.mpg'. Filenames that don't contain '@S' don't need to be renamed.

I parse the filename into an array (using tr) which works. I however don't seem to be able to determine the number of elements of the array. It either gives me the length of the element (when I use dash as the shell) or it gives the length 1 for any parsed filename if I use bash. I've tried to change ${#arr[*]} to ${#arr[@]} but that does not help. The rest of the code works (as far as I currently can see); it indeed populates the variable newname with the correct filename (so the array contains multiple elements if the original filename contains '@S'.

Code:

#!/bin/bash
if [ $# -ne 1 ]; then
  echo "Usage: $0 pathtoassets"
  exit
fi

for f in $1/*.mpg
do
  #parse filename
  arr=$(echo $f | tr "@S" "\n");
  # get number of elements in array
  len=${#arr[*]}
  echo elements:  $len


  # create new filename
  newname=""
  for x in $arr
  do
    newname=$newname@$x
  done

  #rename filename
  echo "moving $f to $newname"
#  mv $f $newname

done

A possible workaround is to compare the filenames to the new filename before moving but I like to know why I can't determine the number of elements in the array.

Thanks in advance

PS running Ubuntu 10.04 for development and it needs to be moved to a Fedora system but I will take that hurdle later.

PPS
There is still a bug in the newname creation but I will solve that myself.

bigearsbilly 07-10-2012 02:44 AM

Code:

for f in *@S1*;do echo mv $f ${f/@S/@} ;done
my motto:
If you are using shell arrays, it's time to think again.

Wim Sturkenboom 07-10-2012 03:20 AM

Thanks; I don't script too often so lack experience on what is available and I live from internet examples ;)

I encountered some issues with the use of 'tr' (it uses each of the characters in the first argument as a separator) so was looking at another solution and indeed dropped the array completely.

Code:

#!/bin/bash
if [ $# -ne 1 ]; then
  echo "Usage: $0 pathtoassets"
  exit
fi

shopt -s nullglob
for f in $1/*.mpg
do
  # generate new filename
  newname=${f//"@S"/"@"}

  #rename filename
  if [ "$f" == "$newname" ]; then
    echo "skipping $f"
  else
    if [ -f $newname ]; then
      echo "skipping $f; will not overwrite existing file $newname"
      continue
    fi
    echo "moving $f to $newname"
    mv "$f" "$newname"
  fi
done

Leaves the question WHY I can't determine the length of the array?

grail 07-10-2012 03:25 AM

Firstly I agree with the above, but as to a solution to your question, you did not create an array, hence you are not getting the results you expect:
Code:

arr=$(echo $f | tr "@S" "\n")

arr=($(echo $f | tr "@S" "\n"))

First example (yours) assigns a the string output of the commands to 'arr', which by the way looks like:
Code:

wim

1.mpg

(Your tr replaces each character with a new line, which might also not be what you expected)

The second example uses () to let bash know that you are assigning an array. It will show an answer of only 2 elements but I caution you against your current solution.

grail 07-10-2012 03:28 AM

You may need to be careful with your changes, // and / as a replacement do different things.

Wim Sturkenboom 07-10-2012 04:00 AM

Quote:

Originally Posted by grail (Post 4723723)
Firstly I agree with the above, but as to a solution to your question, you did not create an array, hence you are not getting the results you expect:
...
...

Thanks, that explains it

Quote:

Originally Posted by grail (Post 4723726)
You may need to be careful with your changes, // and / as a replacement do different things.

// replaces all '@S' while / only does the first one. If I'm incorrect, please correct me. Source: table B-5 at http://www.tldp.org/LDP/abs/html/refcards.html#AEN22587

I indeed want to replace every '@S' by '@'.

Thanks again, billy and grail

grail 07-10-2012 09:57 AM

No you are correct ... just didn't want you to get caught with another not predicted result :)

Wim Sturkenboom 07-10-2012 11:39 PM

The single slash gave me the unpredicted result :D Thanks


All times are GMT -5. The time now is 08:38 PM.