free software resistance
the cost of computing freedom is eternal vigilance
### another-quick-utility-written-with-fig---scounter
*originally posted:* jul 2024
the thing i use fig for the most is creating quick, simple utilities. i could do this in python, or awk if i really wanted to- i could even create this as a javascript widget with the textarea, but the fastest way for me to write this is with the simple commands native to fig.
i want to find which files have the greatest number of subfolders. i accomplish this task simply, then figure out a simpler way to do it after the fact. i will walk you through the process of creating this simple program.
first, we want to be able to pipe the find command to "scounter.fig". this stands for slash counter because thats how it works, but it could also stand for subdirectory, or subfolder counter. im not defending this as a great name or anything:
```
p arrstdin
forin each p
next
```
arrstdin lets you pipe stdout to an array, named p. the variable "each" is used when looping through that array.
there are several ways to count the slashes in each line, but one of the easiest is to split the line by the string youre counting, get the length and subtract 1:
```
p arrstdin
forin each p
scount split each "/" len minus 1
next
```
now we decide what to do with the value scount, which already has the information we need about each line. what im going to do is print the count, which is the number of subfolders (plus one, but more about that in a moment) and then print the actual line.
the reason im printing the actual line is that the point is to find actual paths that are longer than we want- particularly the longest. so to print the count and then the line:
```
p arrstdin
forin each p
scount split each "/" len minus 1
now scount prints " " prints
now each print
next
```
im assuming thousands of lines, and i only want to show the longest of them. since a filesystem of millions of files could take a while, i want to show something while its working, so i decide to let it show any line that ISNT shorter than the longest one found so far.
this is very easy to do. first set up a backup variable, im calling it oc for oldcount, which would be a better name too- and then whenever scount is MORE than the old count, oc gets updated:
```
oc 0
p arrstdin
forin each p
scount split each "/" len minus 1
ifmore scount oc
oc scount
next
now scount prints " " prints
now each print
next
```
now we only show scount and lines that are equal to the largest line found so far:
```
oc 0
p arrstdin
forin each p
scount split each "/" len minus 1
ifmore scount oc
oc scount
next
ifequal scount oc
now scount prints " " prints
now each print
next
next
```
and thats it! each time a path with more folders is found, it will show lines with that many subfolders, until it finds a path with more than that. it does exactly what i need to get back to the real task i was working on- fixing a collection of files that have as many as 8 subfolders.
thanks to this tool, it took only seconds to find those.
note that since i usually run "find ." each path will start with ./ so files with ZERO subfolders show ONE slash:
```
1 ./hello.txt
```
we could change "minus 1" to "minus 2" to sort of fix this, or alternatively we could strip any leading "./" and/or "/" from each line, but then its counting subfolders more precisely, and it really only counts slashes. this might make the program nicer, but it wont make it more useful for what i actually use it for.
another thing that might make it nicer would be to buffer the output so it ONLY shows the largest count and lines with that count. thats the necessary information, but the compromise of this design is 1. less coding to write it, 2. less code to maintain, 3. gives SOME updates and feedback prior to giving the output you actually want. i went with the design i wanted.
but suppose we want EVERY line instead? you have millions of lines, it would show millions of lines.
thats even easier to do. the only lines needed for that were:
```
p arrstdin
forin each p
scount split each "/" len minus 1
now scount prints " " prints
now each print
next
```
and without the ifequal conditional, the line that prints scount can be combined- if you want- with the line that finds scount too:
```
p arrstdin
forin each p
scount split each "/" len minus 1 prints " " prints
now each print
next
```
so the version i showed first does what i want, but if you would rather show every line, those five lines of code are sufficient and can be used on the command line like this:
```
find . -type f | ./scountwo.fig.py | sort -n
```
it will still show the largest lines (by folder count) after the others, but now it will show all the lines before that, too.
i thought of doing this after i wrote the complex version, and i think youll also sometimes find that when you design for simplicity, sometimes the second verson is simpler because of lessons from the first design.
scountwo.fig "compiles" to scountwo.fig.py. you can rename that python file scountwo.py, or even just scountwo, if you want to use it like other commands on your system.
and just to be clear, the more complex design SHOULD show ALL of the lines with the MOST subfolders- every single one. but the minute it finds a path with 3 or 4 subfolders, its not going to show any more lines which have less than that. once youve moved things around so there are no longer 8-subfolder paths for example, youll want to run it again to show what has 7 or whatever the most is. that was the idea of the more complex version.
license: 0-clause bsd
```
# 2018, 2019, 2020, 2021, 2022, 2023, 2024
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
```
=> https://freesoftwareresistance.neocities.org