1

I am trying to list all subdirectories with the lowest number.

For example, for the following list:

/100/2001  
/100/2003  
/101/2001  
/101/2004  
/102/2000  
/102/2003  
/102/2005  

I am looking to obtain only:

/100/2001  
/101/2001  
/102/2000
2
  • Do you provide this input for the wanted solution or shall the solution generate it itself? If the latter: Are there always two levels? Are all entries guaranteed to be numbers? May 6, 2014 at 9:46
  • 1
    On that particular input, GNU uniq -w4 would be enough. May 6, 2014 at 10:36

5 Answers 5

1

For the lowest directory from each directory, you will need to sort the output in each directory.

/100/2001
/100/2003
/101/2001
/101/2004
/102/2000
/102/2003
/102/2005

the ls command automatically does that, but it does alpha-numeric sorting by default. If all your sub-subdirectories have names with the same length then that will be acceptable.

SUBDIRLIST=10? for SUBDIR in $SUBDIRLIST do ls -d $SUBDIR/???? | head -1 done

How this works: for SUBDIR in $SUBDIRLIST
Look in each directory in the list. The list is defined in the previous line. I chose to use 10? to select entries that are three characters long and start with 10 but you could just as well have said SUBDIR=* if you want to use everything.

ls -d $SUBDIR/????

  • ls command to display sorted entries of the contents of $SUBDIR
  • The ???? selects only entries that are four characters long. You may want to choose * if you don't care, or if you have other directories that should be ignored, limit it further using an expression like 20??

| head -1 - Pass the list through the "head command" - Head will display only the first line and discard the rest.

You need a slightly different solution if all the directory names are not the same length, eg:
SUBDIRLIST=10? for SUBDIR in $SUBDIRLIST do find $SUBDIR -depth 1 | sort -n | head -1 done

In this case we use find because ls would sort the entries, but it would do it wrong, so it is redundant. Find doesn't sort the entries (be default).

sort -n then sorts the found items, where -n makes sure they are treated as numbers, so that 20 comes before 100.

Once again head -1 discards everything except the first line.

And finally the SUBDIRLIST=10? statement selects only subdirectories starting with 10 and having three characters in the name. You can limit it more or less, depending on your needs. For example SUBDIRLIST=* selects everything, SUBDIRLIST=??? selects all entries having three characters.

0

This should do the trick:

ls -1d /*/200{0,1}

Ouput:

/100/2001
/101/2001
/102/2000
1
  • way to specific...
    – Jasper
    May 6, 2014 at 9:53
0

For this input this can be done with:

awk -F/ 'min[$2]==0 { min[$2]=$3; next; }; 
 { if (min[$2]>$3) min[$1]=$3;}; 
 END {for (val in min) { print "/" val "/" min[val] };}'

awk sorts by the first field. I don't know whether this is guaranteed or just coincidence. To be sure you may pipe the awk output into

sort --field-separator=/ -n
3
  • 1
    The order is unspecified. That varies from one implementation to the next. Using --field-separator (-t portably) without -k has no effect. Use sort -nt/ -k1,1 -k2,2 May 6, 2014 at 10:45
  • (more -k2,2 -k3,3 as the first field is the empty one at the start) May 6, 2014 at 10:52
  • @StephaneChazelas That was my problem with awk, too... May 6, 2014 at 10:58
0

In Perl:

perl -le 'for (</*/*>){ 
              ($first,$second)=(split m{/})[1,2]; 
              push @{$entries{$first}},$second 
          }
          END{
              for (sort {$a<=>$b} keys %entries){
                  $lowest = shift sort {$a<=>$b} @{$entries{$_}};
                  print "/$_/$lowest\n";
              }
          }'

This assumes all your directories will have purely numerical names.

-1

Something like this?

for firstdir in `ls .`; do
  seconddir=`ls -1 ./$firstdir | head -n 1`
  echo $firstdir/$seconddir
done

note: this script will fail when the second directory have different digits number

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .