Menyembunyikan input pengguna pada terminal di skrip Linux


121

Saya memiliki skrip bash seperti berikut:

#!/bin/bash

echo "Please enter your username";
read username;

echo "Please enter your password";
read password;

Saya ingin bahwa ketika pengguna mengetikkan kata sandi di terminal, itu tidak boleh ditampilkan (atau sesuatu seperti *******) harus ditampilkan). Bagaimana saya mencapai ini?


2
Catatan umum hanya untuk mencegah kebingungan: nama pengguna / kata sandi ini tidak ada hubungannya dengan nama pengguna / kata sandi linux - Saya hanya mencari cara untuk menyembunyikan data yang diketik pengguna selama "baca kata sandi".

Saya menambahkan pembaruan untuk jika Anda ingin menjadi mewah dengan mengeluarkan *saat mereka mengetikkan kata sandi
SiegeX

Terimakasih banyak. Satu pertanyaan jika seseorang tahu - apakah ini otomatis mencegahnya masuk ke .bash_history?


2
Saya tidak berpikir itu akan terjadi, bash_history hanya menangkap perintah Anda, apa yang terjadi setelah menjalankan perintah Anda tidak ditangkap.
Andreas Wong

Jawaban:


272

Cukup berikan -s ke panggilan baca Anda seperti ini:

$ read -s PASSWORD
$ echo $PASSWORD

9
Saya lebih suka cara ini. Saya akan memilih Anda Jika saya tidak mencapai batas harian saya
SiegeX

4
Untuk memberikan konteks: tidak-s menampilkan apa pun saat input diketik. ( -sadalah ekstensi non-POSIX, jadi tidak semua shell mendukungnya, seperti ashshell yang disertakan dengan BusyBox; gunakan ssty -echopendekatan pada shell tersebut)
mklement0

3
@electron Tidak ada di manhalaman ini yang benar-benar menyarankan agar -swarna teks disetel sama dengan warna latar belakang. Itu hanya "bergema diam-diam". ss64.com/bash/read.html Silent mode. If input is coming from a terminal, characters are not echoed.
Andreas Wong

2
@elektron yang saya uji pada kotak saya, tidak hanya itu tidak menggerakkan kursor, ketika saya mencoba menyorot baris tempat saya mengetikkan kata sandi, sepertinya saya tidak dapat menempelkannya nanti. Keduanya harus terjadi jika apa yang dikatakan buku itu benar. Saya menduga mungkin rasa cangkang yang berbeda (saya menggunakan bash 4.1.2 (1)).
Andreas Wong

1
@DominykasMostauskis ya tapi labelnya untuk bash, oleh karena itu solusinya. Mungkin ada banyak varian shell di mana ini tidak berfungsi :)
Andreas Wong

25

Memperbarui

Jika Anda ingin menjadi mewah dengan mengeluarkan *untuk setiap karakter yang mereka ketik, Anda dapat melakukan sesuatu seperti ini (menggunakan read -ssolusi andreas ):

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

Tanpa mewah

echo "Please enter your username";
read username;

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

Ini harus dilakukan IFS=$'\n'agar Anda benar-benar dapat menyelesaikan pengetikan kata sandi. Jika tidak bagus; sangat pintar.
sorpigal

2
Tidak perlu disetel IFS=$'\n'karena pembatas default read adalah -d $'\n'. Pernyataan if untuk memutuskan string nul, yang terjadi pada baris baru, memungkinkan mereka menyelesaikan sandi.
SiegeX

Dalam pengujian di FreeBSD dengan bash 3.x saya menemukan ini tidak terjadi. Pengujian di Linux dengan 3.1.17 memberikan hasil. Saya belum memiliki kotak BSD yang berguna saat ini tetapi saya akan mencoba untuk memastikannya besok, hanya demi rasa ingin tahu saya sendiri.
sorpigal

@Sorpigal: menarik, beri tahu saya apa yang Anda temukan. Saya semua tentang portabilitas
SiegeX

2
Aku memahaminya. Tes FreeBSD saya didasarkan pada kode yang disalin dan ditempelkan dari hasil edit asli Anda yang salah pada kiriman lesmana, yang mengandung satu perbedaan penting: Anda telah melewati reada -d ''. Ketika saya mencobanya lagi nanti di Linux, saya menggunakan versi yang sudah diposting ulang. Jika saya mencoba menghilangkannya, -d ''tentu saja ini berfungsi sama di FreeBSD! Saya sebenarnya cukup lega bahwa tidak ada sihir platform misterius yang bekerja di sini.
sorpigal

17

untuk solusi yang bekerja tanpa bash atau fitur tertentu dari readAnda dapat menggunakan sttyuntuk menonaktifkan gema

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

9

Berikut adalah variasi dari *solusi pencetakan luar biasa @ SiegeX bash dengan dukungan untuk backspace yang ditambahkan; ini memungkinkan pengguna untuk mengoreksi entri mereka dengan backspacekunci ( deletekunci pada Mac) , seperti yang biasanya didukung oleh petunjuk kata sandi:

#!/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

catatan:

  • Adapun mengapa menekan backspace mencatat kode karakter 0x7f: "Dalam sistem modern, tombol backspace sering dipetakan ke karakter hapus (0x7f dalam ASCII atau Unicode)" https://en.wikipedia.org/wiki/Backspace
  • \b \bdiperlukan untuk memberikan tampilan menghapus karakter ke kiri; hanya menggunakan \bmemindahkan kursor ke kiri, tetapi membiarkan karakter tetap utuh ( spasi mundur tidak merusak ). Dengan mencetak spasi dan mundur lagi, karakter tersebut tampaknya telah dihapus (terima kasih, Karakter escape "backspace" '\ b' di C, perilaku tak terduga? ).

Dalam POSIX-satunya shell (misalnya, shpada Debian dan Ubuntu, di mana shadalah dash), menggunakan stty -echopendekatan (yang suboptimal, karena mencetak apa-apa ), karena readbuiltin tidak akan mendukung -sdan -npilihan.


Terima kasih, @Dylan. Saya baru menyadari bahwa kode untuk menghapus karakter terakhir dari kata sandi yang diketik sejauh ini dapat disederhanakan - lihat pembaruan.
mklement0

3

Sedikit berbeda dari (tapi kebanyakan suka) jawaban @ lesmana

stty -echo
read password
stty echo

sederhananya: sembunyikan gema apakah barang Anda menunjukkan gema


Bisakah Anda menjelaskan mengapa ini lebih baik daripada jawaban @ lesmana ? Saya melihat itu lebih sederhana dengan lebih sedikit overhead untuk sttypanggilan lain , dan satu variabel yang lebih sedikit di stack - hanya menghilangkan gema dan hanya memulihkan gema. Apakah ada kemungkinan hal ini dapat mengganggu sttypengaturan lain ? Lesmana's mempertahankan semua pengaturan.
Jeff Puckett

2

Berikut adalah variasi jawaban @ SiegeX yang berfungsi dengan shell Bourne tradisional (yang tidak mendukung +=penugasan).

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

Shell Bourne tradisional (atau yang kompatibel dengan POSIX) juga tidak akan mengenali [[ ... ]], dan readbawaannya juga tidak memiliki opsi -sdan -n. Oleh karena itu, kode Anda tidak akan berfungsi dash, misalnya. (Ini akan bekerja pada platform di mana shsebenarnya bash, seperti di OSX, di mana bashketika dipanggil shhanya mengubah beberapa opsi default sambil tetap mendukung sebagian besar bashisme.)
mklement0

2
Terima kasih atas umpan baliknya, beralih ke tunggal [tetapi jelas tidak banyak yang dapat saya lakukan jika Anda readtidak memiliki opsi ini.
tripleee

2

Saya selalu suka menggunakan karakter pelarian Ansi:

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

8m membuat teks tidak terlihat dan 0m menyetel ulang teks ke "normal". -E membuat Ansi kabur.

Satu-satunya peringatan adalah Anda masih dapat menyalin dan menempelkan teks yang ada di sana, jadi Anda mungkin tidak boleh menggunakan ini jika Anda benar-benar menginginkan keamanan.

Ini hanya memungkinkan orang tidak melihat sandi Anda saat Anda mengetiknya. Hanya saja, jangan tinggalkan komputer Anda setelah itu. :)


CATATAN:

Di atas adalah platform independen selama mendukung urutan escape Ansi.

Namun, untuk solusi Unix lainnya, Anda dapat mengatakan readuntuk tidak menggemakan karakter ...

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

1

Dapatkan Username dan password

Buat agar lebih jelas untuk dibaca tetapi letakkan di posisi yang lebih baik di atas layar

#!/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
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.