以下Haskell程序会提示用户输入终端中的密码,如果他输入了正确的密码则继续:
main = do
putStrLn "Password:"
password <- getLine
case hash password `member` database of
False -> putStrLn "Unauthorized use!"
True -> do
...
不幸的是,密码会在用户输入时显示在屏幕上,我想避免使用。
如何在不显示屏幕的情况下阅读用户输入的一系列字符?为此目的,
getLine
的等价物是什么?
我使用的是MacOS X,但我希望这也适用于Windows和Linux。
答案 0 :(得分:34)
这样做:
module Main
where
import System.IO
import Control.Exception
main :: IO ()
main = getPassword >>= putStrLn . ("Entered: " ++)
getPassword :: IO String
getPassword = do
putStr "Password: "
hFlush stdout
pass <- withEcho False getLine
putChar '\n'
return pass
withEcho :: Bool -> IO a -> IO a
withEcho echo action = do
old <- hGetEcho stdin
bracket_ (hSetEcho stdin echo) (hSetEcho stdin old) action
答案 1 :(得分:13)
System.Console.Haskeline
中有一个getPassword
。可能这对你的案子来说太过分了,但有人可能觉得它很有用。
一个例子:
> runInputT defaultSettings $ do {p <- getPassword (Just '*') "pass:"; outputStrLn $ fromJust p}
pass:***
asd
答案 2 :(得分:9)
可以使用the System.Posix.Terminal
module禁用终端中的回显。但是,这需要POSIX支持,因此可能无法在Windows上运行(我没有检查)。
import System.Posix.Terminal
import System.Posix.IO (stdInput)
getPassword :: IO String
getPassword = do
tc <- getTerminalAttributes stdInput
setTerminalAttributes stdInput (withoutMode tc EnableEcho) Immediately
password <- getLine
setTerminalAttributes stdInput tc Immediately
return password
main = do
putStrLn "Password:"
password <- getPassword
putStrLn "Name:"
name <- getLine
putStrLn $ "Your password is " ++ password ++ " and your name is " ++ name
请注意,stdin是行缓冲的,因此如果使用putStr "Password:"
而不是putStrLn
,则需要先刷新缓冲区,否则也会禁止提示。
答案 3 :(得分:5)
可以用更少的噪音写出来:
withEcho :: Bool -> IO a -> IO a
withEcho echo action =
bracket (hGetEcho stdin)
(hSetEcho stdin)
(const $ hSetEcho stdin echo >> action)
答案 4 :(得分:4)
正如我上面评论的那样,我建议您使用haskeline,这是一个完整的提示库。我很高兴地使用LambdaCalculator而没有任何抱怨。
答案 5 :(得分:0)
我发现在读取密码时这很有用:
import Control.Exception
import System.IO
withoutEcho :: IO a -> IO a
withoutEcho action =
finally (hSetEcho stdin False >> action) (hSetEcho stdin True)