2010-10-31 13 views
23

निम्नलिखित हास्केल कार्यक्रम में एक पासवर्ड के लिए संकेत टर्मिनल में पासवर्ड के लिए उपयोगकर्ता को संकेत देता और अगर वह सही में प्रवेश किया है जारी है:हास्केल कमांड लाइन आवेदन

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

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

दुर्भाग्य से, पासवर्ड पर दिखाई देगा स्क्रीन के रूप में उपयोगकर्ता इसे टाइप करें, जिसे मैं टालना चाहता हूं।

मैं उन वर्णों का अनुक्रम कैसे पढ़ सकता हूं जो उपयोगकर्ता स्क्रीन पर शो के बिना टाइप करते हैं? इस उद्देश्य के लिए getLine के समतुल्य क्या है?

मै मैकोज़ एक्स पर हूं, लेकिन मैं इसे विंडोज और लिनक्स पर भी काम करना चाहता हूं।

+1

उपयोग [haskeline] (http://hackage.haskell.org/packages/archive/haskeline/0.6.3.1/doc/html/System -Console-Haskeline.html # v: getPassword)। –

+1

@TomMd: आपकी टिप्पणी प्रश्न का उचित उत्तर है। इसे वास्तविक जवाब क्यों न दें ताकि इसे वोट किया जा सके, टिप्पणी की जा सके, स्वीकार की जा सके, और कैटर? –

उत्तर

32

अगले का प्रयास करें:

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

एक आकर्षण की तरह काम करता है! क्या आप इसे एक छोटे से पूर्ण 'getPassword :: IO स्ट्रिंग' उदाहरण में बदल सकते हैं, इसलिए मैं इसे स्वीकार्य उत्तर बना सकता हूं? –

+0

मैंने स्निपेट – Yuras

+0

संपादित किया है बहुत बढ़िया, धन्यवाद! –

9

टर्मिनल में the System.Posix.Terminal module के साथ गूंज अक्षम करना संभव है। हालांकि, इसके लिए POSIX समर्थन की आवश्यकता है, इसलिए विंडोज़ पर काम नहीं कर सकता (मैंने जांच नहीं की)।

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 उपयोग करते हैं, आप अन्यथा शीघ्र भी हिचकते हो जाएगा पहले बफर फ्लश करने के लिए की जरूरत है,।

+1

अच्छा, एक अपवित्र है! ऐसा लगता है कि 'System.IO' से विनम्र' hSetEcho' चाल चल जाएगा, हालांकि। :-) –

+0

@ हेनरिक: आह। बहुत नम्र होने के लिए: पी – kennytm

13

System.Console.Haskeline में एक getPassword नहीं है। शायद यह आपके मामले के लिए एक ओवरकिल है लेकिन किसी को यह उपयोगी लगेगा।

एक उदाहरण:

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

अच्छा! मुझे 'हैकलाइन' लाइब्रेरी के बारे में पता नहीं था। –

+1

कोई विचार क्यों सभी हास्कलाइन फ़ंक्शन 'स्ट्रिंग' की बजाय' हो सकता है स्ट्रिंग 'लौटाते हैं? इस पर कोई दस्तावेज नहीं है, और ऐसा लगता है कि इसे हमेशा 'स्ट्रिंग' वापस करना चाहिए, जैसे मानक 'getLine'। – jameshfisher

+0

ऐसा इसलिए है क्योंकि मानक 'getLine' एक आंशिक कार्य है, जो' ईओटी 'प्राप्त करते समय अपवाद उठाएगा। '^ D' – berdario

4

जैसा कि मैंने ऊपर टिप्पणी की, मैं तुम्हें haskeline, जो एक पूर्ण शीघ्र पुस्तकालय है का उपयोग सुझाव देते हैं। मैंने बिना किसी शिकायत के LambdaCalculator के लिए खुशी से इसका इस्तेमाल किया है।

+0

की तुलना में, जब आप खाली रेखा प्राप्त करते हैं, तो आपको कुछ भी अलग करने की इजाजत देनी होगी, किसी भी विचार का कारण है कि सभी हास्कलाइन फ़ंक्शंस' स्ट्रिंग' की बजाय 'शायद स्ट्रिंग' क्यों लौटाते हैं? इस पर कोई दस्तावेज नहीं है, और ऐसा लगता है कि इसे हमेशा 'स्ट्रिंग' वापस करना चाहिए, जैसे मानक 'getLine'। – jameshfisher

+0

@jameshfisher यह मेरे लिए तुरंत स्पष्ट नहीं है, नहीं। यह स्रोत में कुछ खोदना होगा। –

5

withEcho थोड़ा कम noice के साथ लिखा जा सकता है:

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

मुझे लगता है कि यह मेरे लिए थोड़ा सा चालाक है, मुझे यह समझने में काफी मुश्किल लगनी है कि यह कैसे काम करता है। 'अस्थायी रूप से परिवर्तित सेटिंग' व्यवहार को 'withTemp :: a -> IO a -> (a -> IO b) -> IO c -> IO c',' जैसे कुछ 'में' कार्रवाई को अस्थायी रूप से परिवर्तित सेटिंग 'व्यवहार के साथ चलाने के लिए एक बेहतर फ़िक्स हो सकता है। withTemp tempValue गेटर सेटटर एक्शन = ... 'ताकि आप' echo echo = withTemp echo (hGetEcho stdin) (hSetEcho stdin) 'को परिभाषित कर सकें। –