2010-10-31 25 views
23

aşağıdaki Haskell programı bir şifre sormak terminalde bir parola ister ve o doğru olanı girmiş devam eder:Haskell komut satırı uygulaması

main = do 
    putStrLn "Password:" 
    password <- getLine 

    case hash password `member` database of 
     False -> putStrLn "Unauthorized use!" 
     True -> do 
       ... 

Maalesef şifre görünecektir Ekranı kullanıcı olarak yazdığı gibi, kaçınmak istiyorum.

Kullanıcıların ekranda görünmeden yazdığı karakter dizisini nasıl okuyabilirim? Bu amaç için getLine eş değeri nedir?

MacOS X'tayım, ancak bunun Windows ve Linux'ta da çalışmasını istiyorum.

+1

için [haskeline] (http://hackage.haskell.org/packages/archive/haskeline/0.6.3.1/doc/html/System -Konsol-Haskeline.html # v: GetPassword). –

+1

@TomMd: Yorumunuz bu soruya uygun bir cevaptır. Neden oylama yapılabileceğini, yorumlanabileceğini, kabul edilebileceğini ve ne şekilde yorumlanacağını, neden gerçek bir cevap vermeyelim? –

cevap

32

sonraki deneyin:

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 
+3

Bir çekicilik gibi çalışır! Bunu küçük bir "getPassword :: IO String" örneğine dönüştürür müsünüz, bu yüzden kabul edilen cevabı yapabilirim? –

+0

Ben pasajını kaydetmiştiniz – Yuras

+0

Müthiş, teşekkür ederim! –

9

Terminalde yankılanmayı the System.Posix.Terminal module ile devre dışı bırakmak mümkündür. Ancak, bu POSIX desteği gerektirir, bu nedenle Windows üzerinde çalışmayabilir (ben kontrol etmedim). Stdin hattı tamponlu, yani putStr "Password:" yerine putStrLn kullanmak, aksi istemi de inhibe edilecek birinci tampon temizleme için gereken

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 

not edin.

+1

Güzel, bir yükseltiye sahip! Yine de System.IO'dan alçakgönüllü "hSetEcho" gibi görünüyor. :-) –

+0

@Heinrich: Ah. Fark edilmek için çok alçakgönüllü: P – kennytm

13

System.Console.Haskeline bir getPassword yoktur. Muhtemelen senin durumun için bir overkill ama birisi yararlı bulabilir.

Bir örnek: Yukarıda yorumladığı gibi

> runInputT defaultSettings $ do {p <- getPassword (Just '*') "pass:"; outputStrLn $ fromJust p} 
pass:*** 
asd 
+1

Güzel! 'Haskeline' kütüphanesini bilmiyordum. –

+1

Tüm Haskeline işlevlerinin neden bir "String" yerine bir "Belki Dize" döndürdüğüne dair bir fikriniz var mı? Üzerinde herhangi bir belge yok ve bana her zaman '' '' '' '' '' '' '' '' '' '' 'dönüş'ü döndürmelidir. – jameshfisher

+0

standart 'getLine' bir' EOT' alırken durum yükseltecektir kısmi fonksiyonu, çünkü That. haskeline, '^ D' – berdario

4

, sana tam bir istemi kütüphane olduğunu haskeline, kullanmanızı öneririz. Hiçbir şikayeti olmadan LambdaCalculator için mutlu bir şekilde kullandım.

+0

' a kıyasla, boş bir satıra sahip olduğunuzda farklı bir şey yapmanıza izin veren 'Nothing' iadesi yapacaktır. Tüm Haskeline işlevlerinin neden bir' String' yerine 'Belki String' döndürdüğü ile ilgili bir fikriniz var mı? Üzerinde herhangi bir belge yok ve bana her zaman '' '' '' '' '' '' '' '' '' '' 'dönüş'ü döndürmelidir. – jameshfisher

+0

@jameshfisher Hemen açık değil, hayır. Kaynağında biraz kazımak gerekir. –

5

withEcho biraz daha az noice ile yazılabilir:

withEcho :: Bool -> IO a -> IO a 
withEcho echo action = 
    bracket (hGetEcho stdin) 
      (hSetEcho stdin) 
      (const $ hSetEcho stdin echo >> action) 
+1

Bunun benim için biraz fazla zeki olduğunu düşünüyorum, bunun nasıl çalıştığını anlamak için çok zor görünmeliyim. Daha iyi bir düzeltme, 'geçici olarak değiştirilen ayar ile' çalışma eylemini 'gibi bir şeye dönüştürmek olabilir: “TÜM :: a -> IO a -> (a -> IO b) -> IO c -> IO c',' withTemp tempValue getter setter action = ... 'ile, 'withEcho echo = withTemp echo (hGetEcho stdin) (hSetEcho stdin)' öğesini tanımlayabilirsiniz. –