web-dev-qa-db-ja.com

`read`でパスワードを読み取るときに星(*)をエコーするにはどうすればよいですか?

ユーザーがreadを使用して何かを入力したときに、パスワード文字の代わりに*sをエコーする(または単に文字を完全に非表示にする)場合、Bashのコードに対して何をする必要がありますか?

37
Deniz Zoeteman

Mark Rushakoff指摘、read -sは、プロンプトで入力された文字のエコーを抑制します。この機能をこのスクリプトの一部として使用して、入力した各文字のアスタリスクをエコーできます。

#!/bin/bash
unset password
Prompt="Enter Password:"
while IFS= read -p "$Prompt" -r -s -n 1 char
do
    if [[ $char == $'\0' ]]
    then
        break
    fi
    Prompt='*'
    password+="$char"
done
echo
echo "Done. Password=$password"
58

Wironeの答えは本当に気に入りましたが、バックスペースが「パスワードを入力してください」というプロンプトに戻っても文字を削除し続けるのは嫌でした。

また、キーを押すのが速すぎると、一部の文字が実際に画面に印刷されてしまうという問題もありました。パスワードの入力を求めるときは決して良いことではありません。 =)

以下は、これらの問題に対処するWironeの回答の修正版です。

#!/bin/bash

unset PASSWORD
unset CHARCOUNT

echo -n "Enter password: "

stty -echo

CHARCOUNT=0
while IFS= read -p "$Prompt" -r -s -n 1 CHAR
do
    # Enter - accept password
    if [[ $CHAR == $'\0' ]] ; then
        break
    fi
    # Backspace
    if [[ $CHAR == $'\177' ]] ; then
        if [ $CHARCOUNT -gt 0 ] ; then
            CHARCOUNT=$((CHARCOUNT-1))
            Prompt=$'\b \b'
            PASSWORD="${PASSWORD%?}"
        else
            Prompt=''
        fi
    else
        CHARCOUNT=$((CHARCOUNT+1))
        Prompt='*'
        PASSWORD+="$CHAR"
    fi
done

stty echo

echo $PASSWORD
19
Logan VanCuren

read -sはサイレントモードにする必要があります。

-s     Silent mode.  If input is coming from a terminal, characters are not echoed.

man bashreadセクションを参照してください。

12
Mark Rushakoff

Dennis Williamsonのソリューションに何かを追加したいと思います。

#!/bin/bash

unset password
echo -n "Enter password: "
while IFS= read -p "$Prompt" -r -s -n 1 char
do
    # Enter - accept password
    if [[ $char == $'\0' ]] ; then
        break
    fi
    # Backspace
    if [[ $char == $'\177' ]] ; then
        Prompt=$'\b \b'
        password="${password%?}"
    else
        Prompt='*'
        password+="$char"
    fi
done

上記の例では、スクリプトはバックスペースを正しく処理します。

ソース

6
Wirone

星については知りませんが、stty -echoはあなたの友達です:

 #!/bin/sh 
 read -p "Username: " uname 
 stty -echo 
 read -p "Password: " passw; echo 
 stty echo

ソース: http://www.peterbe.com/plog/passwords-with-bash

5
Vinko Vrsalovic

インタラクティブであることを気にしない場合は、単に行うことができます

read -s pass
echo "$pass" | sed 's/./*/g'

これは、入力が押された後、入力されたパスワードの各文字に対して*を表示します。

2
Dino Dini
stty -echo
read something
stty echo

その読み取りのために画面にエコーされるユーザー入力を停止します。プロンプトで何をしているのかに応じて、読み取り後に改行を生成するために、余分なechoコマンドを追加することができます。

2
moonshadow

Dennis Williamson 's、Wirone' s、およびLogan VanCurenの回答に基づいて、このBash固有の関数を作成しました。

ask() {
  local 'args' 'char' 'charcount' 'Prompt' 'reply' 'silent'

  # Basic arguments parsing
  while [[ "${1++}" ]]; do
    case "${1}" in
      ( '--silent' | '-s' )
        silent='yes'
        ;;
      ( '--' )
        args+=( "${@:2}" )
        break
        ;;
      ( * )
        args+=( "${1}" )
        ;;
    esac
    shift || break
  done

  if [[ "${silent}" == 'yes' ]]; then
    for Prompt in "${args[@]}"; do
      charcount='0'
      Prompt="${Prompt}: "
      reply=''
      while IFS='' read -n '1' -p "${Prompt}" -r -s 'char'; do
        case "${char}" in
          # Handles NULL
          ( $'\000' )
            break
            ;;
          # Handles BACKSPACE and DELETE
          ( $'\010' | $'\177' )
            if (( charcount > 0 )); then
              Prompt=$'\b \b'
              reply="${reply%?}"
              (( charcount-- ))
            else
              Prompt=''
            fi
            ;;
          ( * )
            Prompt='*'
            reply+="${char}"
            (( charcount++ ))
            ;;
        esac
      done
      printf '\n' >&2
      printf '%s\n' "${reply}"
    done
  else
    for Prompt in "${args[@]}"; do
      IFS='' read -p "${Prompt}: " -r 'reply'
      printf '%s\n' "${reply}"
    done
  fi
}

次のように使用できます。

$ ask Username
Username: AzureDiamond
AzureDiamond

$ ask -s Password
Password: *******
hunter2

$ ask First Second Third
First: foo
foo
Second: bar
bar
Third: baz
baz
1
nxnev