लिनक्स स्क्रिप्ट में टर्मिनल पर उपयोगकर्ता इनपुट को छिपाना


121

मेरे पास निम्नलिखित की तरह स्क्रिप्ट है:

#!/bin/bash

echo "Please enter your username";
read username;

echo "Please enter your password";
read password;

मैं चाहता हूं कि जब उपयोगकर्ता टर्मिनल पर पासवर्ड टाइप करता है, तो इसे प्रदर्शित नहीं किया जाना चाहिए (या ******* जैसा कुछ प्रदर्शित किया जाना चाहिए)। मुझे यह कैसे हासिल होगा?


2
भ्रम को रोकने के लिए सामान्य नोट: इस उपयोगकर्ता नाम / पासवर्ड का लिनक्स उपयोगकर्ता नाम / पासवर्ड से कोई लेना-देना नहीं है - मैं "रीड पासवर्ड" के दौरान उपयोगकर्ता के प्रकारों को छिपाने के लिए एक तरीका ढूंढ रहा हूं।

मैंने एक अपडेट जोड़ा है कि क्या आप *पासवर्ड टाइप करते हुए आउटपुट प्राप्त करना चाहते हैं
सिएजेक्स

बहुत धन्यवाद। एक सवाल अगर कोई जानता है - क्या यह स्वतः ही इसे .bash_history में जाने से रोक देगा?


2
मुझे नहीं लगता कि यह, bash_history केवल आपकी कमांड को कैप्चर करेगा, आपकी कमांड चलाने के बाद क्या होता है, यह कैप्चर नहीं करता है।
एंड्रियास वोंग

जवाबों:


272

बस आपूर्ति की तरह अपने पढ़ने के लिए कॉल:

$ read -s PASSWORD
$ echo $PASSWORD

9
मुझे यह तरीका बेहतर लगता है। मैं तुम्हें वोट करेंगे, तो मैं अपने दैनिक सीमा हिट नहीं किया
SiegeX

4
संदर्भ प्रदान करने के लिए: इनपुट टाइप किए जाने के दौरान कुछ भी-s प्रदर्शित नहीं होता है। ( -sएक गैर-पॉसिक्स एक्सटेंशन है, इसलिए सभी गोले इसका समर्थन नहीं करते हैं, जैसे ashकि शेल जो ssty -echo
व्यस्त स्विच के

3
@ ईलेक्ट्रॉन manपृष्ठ के कुछ भी नहीं वास्तव में सुझाव है कि -sपाठ का रंग पृष्ठभूमि रंग के समान सेट करता है। यह सिर्फ "चुपचाप गूँजता है"। ss64.com/bash/read.html Silent mode. If input is coming from a terminal, characters are not echoed.
एंड्रियास वोंग

2
@ ईलेक्ट्रॉन मैंने अपने बॉक्स पर परीक्षण किया, न केवल यह कर्सर को स्थानांतरित नहीं करता है, जब मैं उस रेखा को उजागर करने की कोशिश करता हूं जहां मैंने अपने पासवर्ड में टाइप किया था, तो मैं इसे बाद में पेस्ट नहीं कर सकता। अगर किताब कहती है तो सच होना चाहिए। मैं अनुमान लगा रहा हूं कि शायद शेल का एक अलग स्वाद है (मैं बैश 4.1.2 (1) का उपयोग कर रहा था)।
एंड्रियास वोंग

1
@DominykasMostauskis हाँ, लेकिन लेबल बैश के लिए है, इसलिए समाधान। संभवत: कई टन शैल संस्करण हैं जहां यह काम नहीं करता है :)
एंड्रियास वोंग

25

अपडेट करें

यदि आप अपने *प्रत्येक प्रकार के लिए आउटपुट देकर फैंटसी प्राप्त करना चाहते हैं , तो आप ऐसा कुछ कर सकते हैं read -s:

unset password;
while IFS= read -r -s -n1 pass; do
  if [[ -z $pass ]]; then
     echo
     break
  else
     echo -n '*'
     password+=$pass
  fi
done

बिना कल्पना के

echo "Please enter your username";
read username;

echo "Please enter your password";
stty -echo
read password;
stty echo

यह होना चाहिए IFS=$'\n'कि आप वास्तव में कर सकते हैं ताकि खत्म पासवर्ड टाइप। अन्यथा अच्छा; बहुत चालाक।
sorpigal

2
सेट करने की कोई आवश्यकता नहीं है IFS=$'\n'क्योंकि रीड का डिफ़ॉल्ट सीमांकक है -d $'\n'। If-statement एक nul string पर टूटने के लिए, जो एक newline पर होता है, वह वह है जो उन्हें पासवर्ड खत्म करने की अनुमति देता है।
घेराबंदी

बैश 3.x के साथ फ्रीबीएसडी पर परीक्षण में मुझे लगता है कि ऐसा नहीं है। 3.1.17 के साथ लिनक्स पर परीक्षण करने से आपके परिणाम मिलते हैं। मुझे फिलहाल बीएसडी बॉक्स नहीं मिला है, लेकिन मैं कल की पुष्टि करने की कोशिश करूंगा, बस अपनी जिज्ञासा के लिए।
sorpigal

@ सोर्फीगल: दिलचस्प, मुझे पता है कि आपको क्या पता है। मैं सब के बारे में हूँ पोर्टेबिलिटी
SiegeX

2
मुझे मिलगया। मेरा FreeBSD परीक्षण कॉपी किए गए कोड पर आधारित था और आपके मूल गलती से lesmana के पोस्ट को संपादित किया गया था, जिसमें एक महत्वपूर्ण अंतर है: आप readएक गुजर रहे थे -d ''। जब मैंने इसे बाद में लिनक्स पर वापस लिया तो मैंने रीपोस्टेड संस्करण का उपयोग किया। अगर मैं -d ''निश्चित रूप से इसे छोड़ने की कोशिश करता हूं तो यह FreeBSD पर समान रूप से काम करता है! मैं वास्तव में काफी राहत महसूस कर रहा हूं कि यहां काम में कुछ रहस्यमयी मंच जादू नहीं है।
sorpigal

17

एक समाधान के लिए जो बग या बिना कुछ विशेषताओं के काम करता है, readआप sttyइको को अक्षम करने के लिए उपयोग कर सकते हैं

stty_orig=$(stty -g)
stty -echo
read password
stty $stty_orig

9

यहाँ बैकस्पेस के लिए समर्थन के साथ @ SiegeX के उत्कृष्ट -प्रचार *समाधान पर भिन्नता है ; यह उपयोगकर्ता को कुंजी ( मैक पर कुंजी) के साथ अपनी प्रविष्टि को सही करने की अनुमति देता है , जैसा कि आमतौर पर पासवर्ड संकेतों द्वारा समर्थित है:bash backspacedelete

#!/usr/bin/env bash

password=''
while IFS= read -r -s -n1 char; do
  [[ -z $char ]] && { printf '\n'; break; } # ENTER pressed; output \n and break.
  if [[ $char == $'\x7f' ]]; then # backspace was pressed
      # Remove last char from output variable.
      [[ -n $password ]] && password=${password%?}
      # Erase '*' to the left.
      printf '\b \b' 
  else
    # Add typed char to output variable.
    password+=$char
    # Print '*' in its stead.
    printf '*'
  fi
done

ध्यान दें:

  • बैकस्पेस रिकॉर्ड कैरेक्टर कोड को दबाने के लिए क्यों 0x7f: "आधुनिक सिस्टम में, बैकस्पेस कुंजी को अक्सर डिलीट कैरेक्टर (0x7f ASCII या यूनिकोड में) मैप किया जाता है" https://en.wikipedia.org/wiki/Backspace
  • \b \bचरित्र को बाईं ओर हटाने के लिए उपस्थिति देने की आवश्यकता है ; बस \bकर्सर को बाईं ओर ले जाता है, लेकिन चरित्र को बरकरार रखता है ( नॉन्डेस्ट्रक्टिव बैकस्पेस)। किसी स्थान को प्रिंट करने और फिर से वापस जाने से, चरित्र मिट गया प्रतीत होता है (धन्यवाद, "बैकस्पेस" एस्केप कैरेक्टर '\ b' सी में, अप्रत्याशित व्यवहार? )।

एक में POSIX-केवल खोल (जैसे, shDebian और Ubuntu है, जहां पर shहै dash), का उपयोग stty -echoदृष्टिकोण (है, जो इनकी वजह से यह प्रिंट कुछ भी नहीं ), क्योंकि readbuiltin का समर्थन नहीं करेंगे -sऔर -nविकल्प।


धन्यवाद, @ डायलन मुझे बस एहसास हुआ कि अब तक टाइप किए गए पासवर्ड से अंतिम चरित्र को हटाने के लिए कोड को सरल किया जा सकता है - अपडेट देखें।
mklement0

3

से थोड़ा अलग (लेकिन ज्यादातर पसंद है) @ lesmana का जवाब

stty -echo
read password
stty echo

बस: इको छिपाओ अपना सामान दिखाओ गूंज


क्या आप बता सकते हैं कि यह @ lesmana के उत्तर से बेहतर क्यों है ? मुझे लगता है कि यह एक और sttyकॉल के लिए कम ओवरहेड के साथ सरल है , और स्टैक पर एक कम चर है - केवल इको को हटाकर केवल इको को पुनर्स्थापित करना। वहाँ किसी भी तरह से यह अन्य sttyसेटिंग्स परेशान हो सकता है ? लेस्माना सभी सेटिंग्स को संरक्षित करती है।
जेफ पकेट ने

2

यहाँ @ SiegeX के उत्तर की भिन्नता है जो पारंपरिक बॉर्न शेल के साथ काम करता है (जिसमें +=असाइनमेंट के लिए कोई समर्थन नहीं है )।

password=''
while IFS= read -r -s -n1 pass; do
  if [ -z "$pass" ]; then
     echo
     break
  else
     printf '*'
     password="$password$pass"
  fi
done

एक पारंपरिक बॉर्न शेल (या एक POSIX- अनुपालन वाला) भी पहचान नहीं [[ ... ]]करेगा, और न ही इसके readबिलिन में विकल्प -sऔर -nविकल्प होंगे। इसलिए आपका कोड dashउदाहरण के लिए काम नहीं करेगा । (यह उन प्लेटफार्मों पर काम करेगा जहां shवास्तव में है bash, जैसे कि OSX, जहां bashजब shकेवल कुछ बशीशों का समर्थन करते हुए कुछ डिफ़ॉल्ट विकल्पों को संशोधित किया जाता है ।)
mklement0

2
प्रतिक्रिया के लिए धन्यवाद, एकल [पर स्विच किया गया, लेकिन जाहिर है कि मैं बहुत कुछ नहीं कर सकता अगर आपके पास readइन विकल्पों की कमी है।
ट्रिपलए

2

मैं हमेशा एनी एस्केप पात्रों का उपयोग करना पसंद करता हूं:

echo -e "Enter your password: \x1B[8m"
echo -e "\x1B[0m"

8mपाठ को अदृश्य बनाता है और 0mपाठ को "सामान्य" बनाता है । -इसे एनी संभव बच निकलता है।

एकमात्र चेतावनी यह है कि आप अभी भी पाठ को कॉपी और पेस्ट कर सकते हैं जो वहां है, इसलिए यदि आप वास्तव में सुरक्षा चाहते हैं तो आपको इसका उपयोग नहीं करना चाहिए।

यह सिर्फ लोगों को आपके पासवर्ड को देखने की अनुमति नहीं देता है जब आप उन्हें टाइप करते हैं। बस बाद में अपना कंप्यूटर न छोड़ें। :)


ध्यान दें:

उपरोक्त प्लेटफ़ॉर्म स्वतंत्र है जब तक कि यह एनी एस्केप सीक्वेंस का समर्थन करता है।

हालांकि, एक और यूनिक्स समाधान के लिए, आप केवल readपात्रों को प्रतिध्वनित नहीं करने के लिए कह सकते हैं ...

printf "password: "
let pass $(read -s)
printf "\nhey everyone, the password the user just entered is $pass\n"

1

उपयोगकर्ता नाम और पासवर्ड प्राप्त करें

इसे पढ़ने के लिए और अधिक स्पष्ट करें लेकिन इसे स्क्रीन पर बेहतर स्थिति में रखें

#!/bin/bash
clear
echo 
echo 
echo
counter=0
unset username
prompt="  Enter Username:"
while IFS= read -p "$prompt" -r -s -n 1 char
do
    if [[ $char == $'\0' ]]; then
        break
    elif [ $char == $'\x08' ] && [ $counter -gt 0 ]; then
        prompt=$'\b \b'
        username="${username%?}"
        counter=$((counter-1))
    elif [ $char == $'\x08' ] && [ $counter -lt 1 ]; then
        prompt=''
        continue
    else
        counter=$((counter+1))
        prompt="$char"
        username+="$char"
    fi
done
echo
unset password
prompt="  Enter Password:"
while IFS= read -p "$prompt" -r -s -n 1 char
do
    if [[ $char == $'\0' ]]; then
        break
    elif [ $char == $'\x08' ] && [ $counter -gt 0 ]; then
        prompt=$'\b \b'
        password="${password%?}"
        counter=$((counter-1))
    elif [ $char == $'\x08' ] && [ $counter -lt 1 ]; then
        echo
        prompt="  Enter Password:"
        continue
    else
        counter=$((counter+1))
        prompt='*'
        password+="$char"
    fi
done
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.