unix command for terminal - view sequences as a single line?

Hello,

I'm looking for some code that will list sequences of files as a single line.

ie, sequences of files like this:

filename.1.ext
filename.2.ext
filename.3.ext
filename.4.ext
filename.5.ext
filename.6.ext
filename.7.ext
filename.8.ext
filename.9.ext
filename.10.ext

would be listed as such:

filename.1-10.ext

-

non-sequenced files would just be listed as usual along with the seq... so this group:

filenameA.1.ext filenameB.1.ext
filenameA.2.ext filenameB.2.ext
filenameA.3.ext filenameB.3.ext
filenameA.4.ext filenameB.4.ext
filenameA.5.ext filenameB.5.ext
filenameA.6.ext filenameB.6.ext
filenameA.7.ext filenameB.7.ext
filenameA.8.ext filenameB.8.ext
filenameA.9.ext filenameB.9.ext
filenameA.10.ext filenameB.10.ext filenameC.1.ext

would list as such:

filenameA.1-10.ext
filenameB.1-10.ext
filenameC.1.ext

This will have to function in the OSX & Lunix terminals.

Every company I've been at so far has had some version of this command but now I find myself at a place that doesn't and oh how I do miss it. Anything appreciated, feel free to mail me directly.

Thanks!

Kent

Try:

ls | perl -F"\." -nae 'push @{$a{$F[0]}},$F[1];END{for $i (keys %a){@n=sort {$a <=> $b}@{$a{$i}};print "$i.$n[0]-$n[$#n].$F[2]"}}'

Thanks!

For these files:

ls
contacts.1.txt contacts.2.txt contacts.3.txt contacts.txt icc.txt ideas.txt notes (Autosaved) notes.txt shownotes_001.txt shownotes_AllShowsShotList_001.txt

that gives me these results:

ls | perl -F"\." -nae 'push @{$a{$F[0]}},$F[1];END{for $i (keys %a){@n=sort {$a <=> $b}@{$a{$i}};print "$i.$n[0]-$n[$#n].$F[2]"}}'

contacts.txt
-3.notes (Autosaved)
.-.icc.txt
-txt
.shownotes_AllShowsShotList_001.txt
-txt
.notes.txt
-txt
.shownotes_001.txt
-txt
.ideas.txt
-txt
.~/notes/ :

What I really am looking for would be this:

contacts.1-3.txt
contacts.txt
icc.txt
ideas.txt
notes (Autosaved)
notes.txt
shownotes_001.txt
shownotes_AllShowsShotList_001.txt

I found another script:

#!/usr/bin/perl
use strict;

#
# lfrms - list frame ranges
# 1.00 01/12/98 erco@3dsite.com
#

$| = 1;

# MAIN
{
my $dir;
my @curdir = ( "." );
my @dirs = ( $#ARGV == -1 ) ? @curdir : @ARGV;

foreach $dir \( @dirs \)
\{
    if \( $\#dirs &gt; 0 \) \{ print "$dir:\\n"; \}
    my @list = split\(/\\n/, \`ls $dir\`\);
    my @last = "";
    my $start;
    my $pending = 0;

    foreach \( @list \)
    \{
        if \( /\(.\*\)\\.\([0-9]\*\)\\.\(.*\)/ \)
        \{
            \# NO MATCH ON LAST NAME? SKIP
            if \( $1 ne $last[0] || $3 ne $last[2] || \($2-$last[1]\) != 1 \)
            \{
                \# END LAST RANGE
                if \( $last[0] ne "" && $last[2] ne "" \)
                \{
                    if \( $start == $last[1] \) 
                        \# JUST ONE FRAME? PRINT IT
                        \{ printf\("%s.%s\\n", $start, $last[2]\); \}
                    else
                        \# RANGE? PRINT AS RANGE
                        \{ printf\("[%s-%s].%s\\n", $start, $last[1], $last[2]\); \}
                \}

                \# START NEW RANGE
                printf\("%s.", $1\);
                $start   = $2;
                $pending = 1;
            \}

            \# SAVE FOR NEXT ITER
            $last[0] = $1; $last[1] = $2; $last[2] = $3;
        \}
    \}
    if \( $pending \) 
    \{
        if \( $start == $last[1] \) 
            \# JUST ONE FRAME? PRINT IT
            \{ printf\("%s.%s\\n", $start, $last[2]\); \}
        else
            \# RANGE? PRINT AS RANGE
            \{ printf\("[%s-%s].%s\\n", $start, $last[1], $last[2]\); \}
    \}
\}

}

That returns this:

contacts.[1-3].txt

Which is close to how I'd like the files listed but unfortunately drops the non-sequential files. Would it be easy to modify that command to include the non-sequential files?

Thanks again for offering that.

Try:

ls | perl -F"\." -nae 'if ($F[2]){push @{$a{$F[0]}},$F[1];$e{$F[0]}=$F[2]}else{$a{$_}=1};END{for $i (keys %a){@n=sort {$a <=> $b}@{$a{$i}};if (@n){print "$i.$n[0]-$n[$#n].$e{$i}"}else{print $i}}}'

Thank you! This is great, does exactly what I need.

I'm having a problem getting it into action though. In my .alias file though, I get a message about an 'unmatched parenthesis' when I source the file, and if I make it into a command .csh file in the /bin dir I get a message about a misplaced ' .

The sorting on the non-sequential files is non-alphabetical though... but of course thats a minor thing.

I'll work it a bit to see if I can get it into my .alias file or into .csh file.

Thanks very much!

There are a lot of unsolvable quoting problems in csh, among many other flaws, to the point diatribes have been written about it. Its inventor admits he "wasn't too good at programming" when he wrote it. What if you put it in a bourne script with #!/bin/sh instead?

I haven't tried that, but there is unfortunately a bigger problem with it in that if there are breaks in a sequence this cmd won't show them. For example if there is a range of files like this:

filename.1.ext
filename.2.ext
filename.3.ext
filename.4.ext

filename.6.ext
filename.7.ext
filename.8.ext

then the result is still

filename.1-8.ext

which is not useful. It would need to read out as such:

filename.1-4.ext
filename.6-8.ext

-

Regarding getting it to a form where I can link a shortened cmd to is, someone else suggested this:

"The simplest thing to do is toss that one-liner into an executable file, and modify your alias to pipe the output of ls into that. The next simplest thing to do is switch to bash (assuming you're not using it already), and put it into a function. Otherwise, put a ' (single quote) at the start, and every time you get to a single quote, end the previous quote, wrap the single quote in double quotes, and then start with another single quote:

'ls | perl -F"\\." -nae '"'"'if...

You might consider replacing the internal double quotes with qq(), too."