Read a line the person types at the terminal, and read a password without showing it.
import sys
sys.write("Your name: ")
let name = sys.readline()
print(`hello, {name}`)
$ scua --allow-tty greet.scua
Your name: Ada
hello, Ada
#Reading the terminal needs a grant
sys.readline and sys.readpassword need
--allow-tty. Without it they do not exist,
and the compiler tells you so by name rather than failing at run
time:
greet.scua:4: `sys.readline` requires the `tty` capability, which this run was not granted —
grant it with `--allow-tty` on the CLI, or the host's capability API when embedding
--allow-all and a capability file
(tty = true under [capabilities]) grant it
too.
The grant exists because the terminal is where a person types secrets. It is also never inherited by a partition: an actor cannot read the terminal even when the program that spawned it can. Read at the top level and pass the value in.
#Always guard for the end of input
Both readers return nil when there is
no more input — a closed pipe, Ctrl-D, or a run with no
terminal at all. That is not an error; it is what unattended looks
like:
let name = sys.readline()
if name == nil then
print("no input — running unattended")
else
print(`hello, {name}`)
end
Skip the guard and len(name) faults the first time
someone pipes your script into something. The same script then works in
all three shapes:
$ scua --allow-tty greet.scua # a person types
$ printf 'Ada\n' | scua --allow-tty greet.scua # piped
$ scua --allow-tty greet.scua < /dev/null # unattended
#Passwords
sys.readpassword reads a line with the terminal's echo
turned off, so the secret is not displayed and does not reach your
scrollback.
sys.write("Password: ")
let pw = sys.readpassword()
if pw == nil then
print("no password given")
else
print(`got {len(pw)} characters`)
end
Three things worth knowing.
Pasted-ahead input is discarded. If you paste
name⏎secret⏎ at the first prompt, the terminal has
already displayed the secret — it landed in the field above, which was
still echoing. No program can un-display it. What SCUA does is refuse to
use it: anything typed ahead is thrown away and you are
prompted again. Re-type at the quiet prompt.
On a pipe there is no echo to suppress, so
readpassword simply reads.
printf 'pw\n' | prog works, which is what makes scripts
testable.
The secret is an ordinary string. It lives in memory like any other value — it can be copied, printed if you print it, and saved if you save it. SCUA does not scrub it. Treat it the way you would in any language: use it, do not store it.
#Don't mix
sys.readline with sys.stdin()
sys.stdin()
hands you the whole of standard input as one string. On a pipe, both
draw from the same bytes — so using both means one of them takes input
the other expected, and which one wins depends on the order you call
them.
Pick one. sys.stdin() for a payload piped in;
sys.readline for a conversation.
#Timers keep running while you wait
Waiting for input does not freeze the program: host timers continue
to run while the prompt sits there. What you cannot do is read from
inside a spawned task or an actor handler — that is
refused, because it would silently stall everything else running
alongside it.
#See also
examples/interactive.scua— the runnable version of this page- Read command-line
arguments —
sys.args, andsys.stdin()for a piped payload