Remix.run Logo
aozgaa 3 hours ago

Another solution to the pipeline example, this time making use of a subprogram for the frequency/accumulation:

    < README.md \
      tr -c '[:alpha:]' '\n' \
    | tr '[:upper:]' '[:lower:]' \
    | awk '
        NF {
          if (!($0 in count)) order[++n] = $0
          count[$0]++
        }
        END {
          for (i = 1; i <= n; i++) {
            print count[order[i]], order[i]
          }
        }
    '
If you don't allow `awk` in your "pure bash" then ofc this is not satisfactory. But it has the upside that the associative arrays are pretty explicit data structures (for the ordering and counts, respectively).
sgarland an hour ago | parent | next [-]

You can skip `tr` as well - works on BSD awk and GNU awk.

    {
        $0 = tolower($0)
        gsub(/[^[:alpha:]]/, "\n")
        for (i = 1; i <= NF; i++) {
            if (!($i in freq)) order[++n] = $i
            freq[$i]++
        }
    } END {
        for (i = 1; i <= n; i++)
            printf "%d %s\n", freq[order[i]], order[i]
    }
JoachimSchipper 2 hours ago | parent | prev [-]

Nice to see more people getting nerdsniped by the sh code. ;-)

Yes, associative arrays work well. I think it should even be possible to use bash associative arrays. But at that point you're no longer doing classic sh - awk is basically halfway to Perl. (And pretty awesome.)