Select Option - Hottest new TUI tool
Howdy gamers! I just created a sweet new tool for bash scripts that have branching logic: select_option!
Simply pipe in data, then a TUI will appear, letting the user select which line they want. Once they press enter (can’t cancel, they must choose) the selected text is put in stdout.
A simple use case is as follows:
lsblk -lno type,name | grep part | awk '{ print "/dev/" $2 }' | select_option | tee file.txt
This (once an option is selected) will output something akin to: /dev/nvme1n1p1 into file.txt.
You can also make really aids scripts like:
exec 4>&1
printf 'a\nb\nc' | select_option | tee /proc/self/fd/4 | xargs -I% echo You selected: %
Which will output (example):
You selcted: c
But you may ask “what is the exec 4>&1 line?
To which I response “Hahahah!! That is my redirect-inator” (In a Dr. Dufinshmertz voice).
But actually that is creating something called a file descriptor.
I’m not going to full explain them here (it would be better to just read that link) but you can think of them as a FIFO queue (first-in-first-out).
We are using this because when select_option takes over the terminal to draw the TUI, it is taking over stdout.
This is why we can’t just input... | select_option | ...outupt because that tries to pipe the TUI into the next command (...output in this case.)
So instead we tee, which writes to a file and stdout.
Not quite sure on the specifics of why this works.
My intuition just said it would and it did.
Regardless - this gives us stdout to use for the TUI, but then duplicates the output to /proc/self/fd/4 - our FIFO queue.
But this fd is special, because we set it, (4), up to redirect it’s input into stdout (1).
This means that xargs can pick it up on it’s stdin (0) pipe, because 4 is redirected to 1 which is redirected to 0.
I split the command into multiple lines (this wouldn’t actually run like this) so I can spam comments. I put the FDs in parentheses (quite verbosely) because 0,1,2 are really just stdin/out/err. I think this helps de-mystifies FDs.
# Setup fd 4 (4) to redirect it's input to stdout (1)
# This creates a new "file" in /proc/self/fd
exec 4>&1
# Put 'a\nb\nc' onto stdout (1)
printf 'a\nb\nc'
# Redirct stdout (1) to stdin (0) of the next command
|
# Read data piped thru stdin (0)
select_option
# Pipe stdout (1) to stdin (0) of next command
|
# Read stdin (0) and pipe it to stdout (1) and fd 4 (4)
tee /proc/self/fd/4
# stdout (1) is captured by the output of select_option and displays the TUI.
# Once select_option is done, it prints it's result to stdout (1) (which is piped to tee's stdin (0)).
# tee then pushes this value to both stdout (1) and fd 4 (4).
# Since fd 4 (4) is redirected to stdout (1), it is then piped to the next command's stdin (0)
|
# xargs reads stdin (0) and operates on it.
# echo puts it's arguments on stdout (1) which we read in the terminal
xargs -I% echo You selected: %
# Final output:
# a
# You selected: a
This still has some weird-ness tho.
If I pipe the output to word count: ... | wc, the characters it sees stays 1, but the bytes it sees increases, meaning that it is getting the whole TUI, but is somehow filtering out just the correct char.
Also, the final output shows the value you selected: ‘a’, but this value was also passed it along to the next command (xargs). The single value ‘a’ doesn’t mess with anything, but I’m not too sure how it escapes “containment”.
If you have questions or comments (you can explain it better than me lol) feel free to reach out!