Linuxスクリプトのターミナルでユーザー入力を非表示にする


121

次のようなbashスクリプトがあります。

#!/bin/bash

echo "Please enter your username";
read username;

echo "Please enter your password";
read password;

ユーザーが端末でパスワードを入力するときに表示されないようにする(または*******のようなものを表示する)必要があります。どうすればこれを達成できますか?


2
混乱を避けるための一般的な注意:このユーザー名/パスワードはLinuxのユーザー名/パスワードとは関係ありません。「パスワードの読み取り」中にユーザーが入力したデータを非表示にする方法を探しています。

*彼らがパスワードを入力している間に出力することで気を使いたい場合のためのアップデートを追加しました
SiegeX

どうもありがとう。誰かが知っている場合の1つの質問-これにより、.bash_historyへの移動が自動的に妨げられますか?


2
私はそうは思いません、bash_historyはコマンドをキャプチャするだけです。キャプチャしないコマンドを実行した後はどうなりますか。
Andreas Wong

回答:


271

次のように、読み取り呼び出しに-sを指定するだけです。

$ read -s PASSWORD
$ echo $PASSWORD

9
私はこの方法が好きです。私が1日の制限に達しなかった場合は投票します
SiegeX 2010年

4
コンテキストを提供するには:入力が入力されている間は何も-s表示しません。(-s非POSIX拡張であるためash、BusyBoxに付属するシェルなど、すべてのシェルがそれをサポートしているわけではありません。ssty -echoそのようなシェルでアプローチを使用してください)
mklement0

3
@electron manページの何も実際には-s、テキストの色を背景色と同じに設定することを示唆していません。それは単に「静かにエコー」します。 ss64.com/bash/read.html Silent mode. If input is coming from a terminal, characters are not echoed.
Andreas Wong、

2
@electronボックスでテストしました。カーソルが動かないだけでなく、パスワードを入力した行を強調表示しようとすると、後で貼り付けることができません。本が言っていることが真実であれば、どちらも起こるはずです。私はおそらくシェルの異なるフレーバーを推測しています(私はbash 4.1.2(1)を使用していました)。
Andreas Wong

1
@DominykasMostauskisそうですが、ラベルはbashのためのものなので、解決策です。これが機能しないシェルバリアントはおそらくたくさんあります:)
Andreas Wong

25

更新

入力した*文字ごとにを出力して凝ったものにしたい場合は、(andreasの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'あなたが実際にできるように終了したパスワードを入力します。そうでなければいい; 非常に賢い。
10

2
IFS=$'\n'読み取りのデフォルトの区切り文字はであるため、設定する必要はありません-d $'\n'。改行で発生するヌル文字列で中断するifステートメントは、パスワードを完成させるためのものです。
SiegeX 2010年

bash 3.xを使ったFreeBSDでのテストでは、これは当てはまりません。Linuxで3.1.17をテストすると、結果が得られます。現時点ではBSDの箱は手元にありませんが、好奇心のために明日確認します。
sorpigal

@Sorpigal:おもしろい、あなたが見つけたものを教えてください。私は移植性についてすべてです
SiegeX 2010年

2
私はそれを持っている。あなたが渡していた:私のFreeBSDのテストは一つの重要な相違点が含まれlesmanaのポストのあなたの元間違わ編集からコピーして貼り付けたコードに基づいていました。後でLinuxで再試行したときに、再投稿されたバージョンを使用しました。もちろん省略しても、FreeBSDでも同じように機能します。ここには、不思議なプラットフォームの魔法が働いていないので、本当に安心しています。read-d ''-d ''
10

17

エコーを無効にするreadためsttyに使用できるbashまたは特定の機能なしで機能するソリューションの場合

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

9

これは、バックスペースのサポートが追加された、@ SiegeXの優れた*印刷ソリューションのバリエーションです。これにより、ユーザーキー(Macのキー)エントリ修正できます。これは通常、パスワードプロンプトでサポートされています。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:「最近のシステムでは、バックスペースキーはしばしば削除文字(ASCIIまたはUnicodeでは0x7f)にマッピングされますhttps://en.wikipedia.org/wiki/Backspace
  • \b \b左側の文字を削除するように見せるために必要です。使用\bするだけでカーソルは左に移動しますが、文字はそのまま残ります(非破壊的なバックスペース)。スペースを印刷して再び戻ると、文字は消去されたように見えます(ありがとう、Cの「バックスペース」エスケープ文字 '\ b'、予期しない動作?)。

ではPOSIXのみ(例えば、シェルshDebianとUbuntuの、上shdash)、使用stty -echoアプローチ(それは印刷していないので、次善のです何を)ので、read組み込みがサポートしています-sし、-nオプションを。


ありがとう、@ Dylan。これまでに入力したパスワードから最後の文字を削除するコードを簡略化できることに気づきました。更新を参照してください。
mklement0 2014

3

@lesmanaの答えとは少し異なりますが(ほとんどの場合)

stty -echo
read password
stty echo

単に:エコーを非表示にする


これが@lesmanaの答えよりも優れている理由を説明できますか?別のstty呼び出しのオーバーヘッドが少なく、スタック上の変数が1つ少なく、エコーを取り除き、エコーのみを復元することで、よりシンプルになっています。これが他のstty設定を混乱させる可能性のある方法はありますか?レスマナはすべての設定を保持します。
Jeff Puckett

2

@SiegeXの回答のバリエーションは、従来のBourneシェル(+=割り当てをサポートしていない)で動作します。

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

従来のBourneシェル(またはPOSIX準拠のシェル)もを認識せず[[ ... ]]、そのread組み込みには-s-nオプションがありません。したがってdash、たとえば、コードはで機能しません。(OSXのようshbash、実際にであるプラットフォームで動作します。ほとんどのバシズムをサポートしながら、いくつかのデフォルトオプションを変更するだけでbash呼び出されshます。)
mklement0

2
フィードバックをありがとう、シングルに切り替えました[が、readこれらのオプションが不足している場合は明らかにできることはありません。
tripleee 2014

2

私は常にAnsiエスケープ文字を使用したいです。

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

8m テキストを非表示にし、 0mテキストを「通常」にリセットします。-eは、Ansiエスケープを可能にします。

唯一の注意点は、そこにあるテキストを引き続きコピーして貼り付けることができることです。そのため、本当にセキュリティが必要な場合は、これを使用しないでください。

それはあなたがそれらを入力するときにあなたのパスワードを見ないようにするだけです。後であなたのコンピュータをそのままにしないでください。:)


注意:

上記は、Ansiエスケープシーケンスをサポートしている限り、プラットフォームに依存しません。

ただし、別のUnixソリューションでは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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.