1

I am building a bash-script to visualize the various fonts available for figlet using figlist.

figlist provides output like this:

Default font: standard
Font directory: /usr/local/Cellar/figlet/2.2.5/share/figlet/fonts
Figlet fonts in this directory:
3-d
3x5
5lineoblique
[...]
twopoint
univers
usaflag
weird
whimsy
Figlet control files in this directory:
646-ca
646-ca2
646-cn
646-cu
[...]
tsalagi
upper
ushebrew
uskata
utf8

The [...]s represent snipped output. My desired output is the following:

3-d
3x5
5lineoblique
[...]
twopoint
univers
usaflag
weird
whimsy

That is, I want the font names. I cannot guarantee the output format, but I don't want any control files, and I don't want the informational lines. I'm not sure, but I suspect all fonts must have one word names, so a regex solution might be possible. However, the control files have a similar format.

Current (hard-coded) solution:

read -a fonts <<<$(figlist | tail -n +4 | head -n 163)

This provides what I want, but requires that the length of the font list never changes, which I don't want.

I would prefer a solution in bash/standard commands/builtins, as that is the language in which I am writing the script, but if it can be obtained via a python one-liner or something similar (e.g. python -c <some command>) then that is acceptable as well.

D. Ben Knoble
  • 4,273
  • 1
  • 20
  • 38

3 Answers3

2

Python one-liner:

figlist | python -c "import sys,re; fonts=re.search(r'Figlet fonts.+?:(.*)(?=Figlet control)',sys.stdin.read(), re.DOTALL); print(fonts.group(1).strip())"

The output:

3-d
3x5
5lineoblique
[...]
twopoint
univers
usaflag
weird
whimsy

That's all, folks

RomanPerekhrest
  • 88,541
  • 4
  • 65
  • 105
  • 1
    Thanks for sharing it sir, you are AWESOME. you are too good in solutions :) – RavinderSingh13 Jul 23 '17 at 07:59
  • 2
    (1) a one liner is code that fit's into one line, not code that should be on multiple lines but you pressed it into one line. (2) A regex is not the right thing to use here in Python. Use `String.startswith()` to check if a string starts with another fixed string. – hek2mgl Jul 23 '17 at 09:37
  • @hek2mgl, he asked *via a python one-liner* and I gaved him one-liner. I know about `str.startwith()` and regex without your advices. So, I don't need your help with that – RomanPerekhrest Jul 23 '17 at 13:26
  • While I'm inclined to agree with @hek2mgl 's interpretation of a *one-liner*, this *is* a valid solution, if difficult to express due to it's length. +1 for a good solution, but I prefer the `awk`. – D. Ben Knoble Jul 24 '17 at 14:35
1

Update:

A shorter and preferable awk alternative would be:

figlist | awk '/Figlet/{p=!p;next}p'

I recommend to use in favour of the below sed command.


Original answer:

You can use sed:

figlist | sed -n '/Figlet fonts/,/Figlet/{//!p;}'

Example:

Print the current user name with each installed figlet font:

figlist \
  | sed -n '/Figlet fonts/,/Figlet/{//!p;}' \
  | while read -r font ; do
        echo "font: ${font}"
        figlet -f"${font}" "$(whoami)"
    done
hek2mgl
  • 152,036
  • 28
  • 249
  • 266
  • Thanks for the quick reply. I'm getting `sed: 1: "/Figlet fonts/,/Figlet/ ...": extra characters at the end of p command` in bash interactively – D. Ben Knoble Jul 22 '17 at 21:20
  • Looks you are on a Mac. Add a `;` after `p`. Edited the code in the answer. – hek2mgl Jul 22 '17 at 21:28
  • `^1` for the awk answer. I would not suggest/use the sed one due to having to specify the same condition multiple times and in the shell loop if you move the pipe to the end of the line instead of the beginning then you don't need the backslashes. – Ed Morton Jul 23 '17 at 12:26
  • 2
    @EdMorton I agree that the `awk` solution is preferable for the reasons you mentioned. I never knew that a command in bash can spread over multiple lines when the last symbol in a line is a pipe. Still I like to have the pipes aligned at the start of the lines. Imo this is simpler to read. (and looks nice ;) ) – hek2mgl Jul 23 '17 at 13:00
  • 1
    That's definitely an eye of the beholder thing - I much prefer the look of pipes (aligned if it makes sense) at the end of lines and the commands involved in the pipeline aligned at the start of lines. IMHO it makes each line clearer on it's own since you can see on each line stand-alone that it's output is going to a pipe (vs being redirected to a file or anything else that could follow a backslash). Essentially it means you don't need to read the next line to know fully what the current line is doing. And it saves a couple of chars and doesn't throw off your normal indenting! nbd though... – Ed Morton Jul 23 '17 at 13:11
  • 1
    @EdMorton Repeated condition can be avoided: `sed -n '/^Figlet fonts/,/^Figlet/{//!p;}'`. – SLePort Jul 24 '17 at 06:08
  • @SLePort Good point. I always miss that! (Well, there might be versions of sed which handle that differently. I couldn't find any ;) ) – hek2mgl Jul 24 '17 at 06:09
1

As this question was tagged also, I feel free to add an awk solution:

/^Figlet fonts/ { on = 1 ; next }
/^Figlet control/ { on = 0 ; next }
on { print $0 }

Test (on bash, cygwin, Windows 10):

$ echo 'Default font: standard
> Font directory: /usr/local/Cellar/figlet/2.2.5/share/figlet/fonts
> Figlet fonts in this directory:
> 3-d
> 3x5
> 5lineoblique
> [...]
> twopoint
> univers
> usaflag
> weird
> whimsy
> Figlet control files in this directory:
> 646-ca
> 646-ca2
> 646-cn
> 646-cu
> [...]
> tsalagi
> upper
> ushebrew
> uskata
> utf8
> ' | awk '/^Figlet fonts/ { on = 1 ; next } /^Figlet control/ { on = 0 ; next } on { print $0 }'
3-d
3x5
5lineoblique
[...]
twopoint
univers
usaflag
weird
whimsy

$
Scheff's Cat
  • 19,528
  • 6
  • 28
  • 56