Incrementing with a twist - please help

I'm currently trying to write a ksh or csh script that would change the name of a file found in directories and attach to the name an incrementing three digit number.
I know how to write a script that will go:
000, 001, 002, 003, etc

The twist is I need more increments then allowed by a 3 digit number so I want to use letters too. For example:
008, 009, 00A, 00B, 00C --- 00Z, 010, 011, 012, 013 --- 099, 0AA, 0AB --- 0ZZ, 100, 101, etc

Any slick ways of doing this? I searched for it but couldn't find anything like this on the forum.

Thanks!

Rust

digits='0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z'
for i in $(eval echo {$digits}{$digits}{$digits}); do echo $i; done

---------- Post updated at 02:34 AM ---------- Previous update was at 02:25 AM ----------

By the way, your example sequence is inconsistent. 09A and 09B should follow 099, not 0AA and 0AB. :wink:

Regards,
Alister

#!/usr/bin/perl

for $i  ( 000 .. 999 ) {
  if ($i < 10 ) {
    $int="00".$i
}
 elsif (( $i >= 10 ) && ( $i < 100 )){
     $int="0".$i
    }
 else {
  $int=$i;
   }

  for $j  ( A .. Z ){
  print "$int$j\n"
}
}

cheers,
Devaraj Takhellambam

Thanks for you help guys. And your right Alister, I was off on my example. :smiley:

Going to test it now.

alister's script is best. Can you explain why "eval" can generate the data automatically?

$ eval echo {$digits}{$digits}{$digits} |more
000 001 002 003 004 005 006 007 008 009 00A 00B 00C 00D 00E 00F 00G 00H 00I 00J 00K 00L 00M 00N 00O 00P
....

Here is my code.

digits='0 1 2 3 4 5 6 7 8 9 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z'
for i in ${digits}
do
  for j in $digits
  do
    for k in $digits
    do
       echo "$i$j$k"
    done
  done
done

Hi, rdcwayx

It's not the eval which generates the data; it's brace expansion.

#Non-numeric example
$ echo f{ee,i,o,um}
fee fi fo fum

#Numeric example
$ echo {0,1}{0,1}{0,1}
000 001 010 011 100 101 110 111

Since the original poster's problem requires a fairly long sequence of digits, for brevity I wanted to avoid:

echo {0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z}{0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F,G,H,etc.....

Storing the list in the variable $digits allows me to do that. However, since brace expansion occurs before variable expansion, we need to send the command line through the shell's parser a second time, using eval. Otherwise we just get:

$ digits=0,1
$ echo {$digits}{$digits}{$digits}
{0,1}{0,1}{0,1}

Instead of:

$ eval echo {$digits}{$digits}{$digits}
000 001 010 011 100 101 110 111

Note: Brace expansion does not occur if there is no unquoted comma within the braces, so we do not need to quote {$digits}.

A downside to this approach is that if the list of digits is long enough, or if there are many braced terms to expand, the list of resulting words could exceed the command line length limit. In such a case, your approach is superior as it never needs to execute a long command line. Another way around this limitation would be to write it out explicitly in the for loop:

$ for i in {0,1}{0,1}{0,1}; do echo $i; done
000
001
010
011
100
101
110
111

IMPORTANT: Brace expansion is not a posix-standardized feature, so if that's a concern, my approach is not an option; yours would be the better choice. Also, the order of brace expansion in relation to parameter expansion as described above is BASH specific (which I chose to use for the illustrative examples since it's much more popular than ksh, and because for this particular scenario it's the more complicated case). In pdksh, ksh88, and ksh93, brace expansion occurs after parameter expansion, not before. So, if using a ksh variant, neither the eval nor the echo nor the command substition is necessary (though in this case their presence does not affect the end result); a simple 'for i in {$digits}{$digits}{$digits}' would be sufficient.

Hope that helps. If not, feel free to ask for clarification.

Cheers,
Alister

Thank you so much for the explanation.

One question for Moderators,

I try to give bits awards to alister's reply, but my ID can't do that now.

I remember I can give before. Can you help?

rdcwayx:

You're very welcome. Regarding the bits, don't worry about it. It's the thought that counts :wink:

Alister

devtakh
perl does it automagically:

#!/usr/bin/perl

$x = "ab8";
foreach (1..10) {

   print $x++, "\n";

}

$ ./1.pl
ab8
ab9
ac0
ac1
ac2
ac3
ac4
ac5
ac6
ac7


That sequence fragment is incorrect. Ignoring case sensitivity, it should be:

ab8
ab9
aba
abb
...snip...
aby
abz
ac0
ac1

Alister

I appreciate all the help and explanation Alister. It is a very clever method of incrementing. Also thanks for the perl examples. Unfortunately I am going to run this script on some older machines and want to use ksh or csh.

Now I'm trying to figure out how to take this constantly increasing number and assign it to a file name when files are put into the directory. So say the last file was renamed to:
7BC.txt
I then copy it somewhere else.

then 10 minutes later another file was dropped in the directory and the script would rename it:
7BD.txt
then copy it.

Right now I have the last incrementing number stored off to a file so I can grab it, but I'm having trouble incrementing it based on what code I've gotten from you guys. I can do this with regular numbers, but not with letters. Please help if you can.

Thanks!

You can do something like this.

Redirect the output of the command to a file "sequences":

000
001
002
.
.
ZZZ

Create a file "ref" with the next line number:

echo "1" > ref

Now you can move the files with this script:

#/bin/sh

num=$(< ref)	# read the linenumber from the file ref
newname=$(awk -v var=$num 'NR==var{print $0 ".txt";exit}' sequences)	# new filename

mv file newname

num=$(( $num + 1 ))	# increase line number
echo $num > ref		# store new number in ref

Regards