Linux komut dosyasında terminalde kullanıcı girişini gizleme


121

Aşağıdaki gibi bash betiğim var:

#!/bin/bash

echo "Please enter your username";
read username;

echo "Please enter your password";
read password;

Kullanıcı terminalde şifreyi girdiğinde görüntülenmemesini (veya ******* gibi bir şeyin görüntülenmesini) istiyorum. Bunu nasıl başarırım?


2
Sadece karışıklığı önlemek için genel not: bu kullanıcı adı / şifrenin linux kullanıcı adı / şifresi ile hiçbir ilgisi yoktur - Ben sadece kullanıcının "şifre oku" sırasında yazdığı verileri gizlemenin bir yolunu arıyorum.

*Onlar şifreyi
yazarken

Çok teşekkürler. Birisi biliyorsa bir soru - bu otomatik olarak .bash_history'ye girmesini engeller mi?


2
Bunun olacağını sanmıyorum, bash_history sadece komutunuzu yakalar, komutunuzu çalıştırdıktan sonra olanları yakalamaz.
Andreas Wong

Yanıtlar:


272

Okuma aramanıza şu şekilde -sağlayın:

$ read -s PASSWORD
$ echo $PASSWORD

9
Bu yolu daha çok seviyorum. Günlük
limitime ulaşmasaydım

4
Bağlam sağlamak için: giriş yazılırken hiçbir şey-s görüntülemez . ( POSIX olmayan bir uzantıdır, bu nedenle BusyBox ile birlikte gelen mermi gibi tüm mermiler onu desteklemez ; yaklaşımı bu tür mermilerde kullanın)-sashssty -echo
mklement0

3
içinde @electron Hiçbir şey mansayfası aslında düşündürmektedir -ssetleri arka plan rengiyle aynı metin rengi. Sadece "sessizce yankılanıyor". ss64.com/bash/read.html Silent mode. If input is coming from a terminal, characters are not echoed.
Andreas Wong

2
@electron Kutumda test ettim, sadece imleci hareket ettirmiyor, şifremi yazdığım satırı vurgulamaya çalıştığımda, daha sonra yapıştıracakmış gibi görünmüyorum. Kitap doğruysa her ikisi de olmalıdır. Tahminimce farklı bir kabuk aroması (bash 4.1.2 (1) kullanıyordum).
Andreas Wong

1
@DominykasMostauskis evet ama etiket bash içindir, bu nedenle çözüm. Bu :) çalışmıyor nerede kabuğun ton Muhtemelen varyantlarıdır
Andreas Wong

25

Güncelleme

Yazdıkları *her karakter için bir çıktı alarak süslü olmak istiyorsanız, şöyle bir şey yapabilirsiniz (andreas'ın read -sçözümünü kullanarak ):

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

Fantezi olmadan

echo "Please enter your username";
read username;

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

Bu olmalı IFS=$'\n'aslında böylece bitirmek şifreyi yazarak. Aksi takdirde güzel; çok zeki.
sorpigal

2
IFS=$'\n'Okumanın varsayılan ayırıcısı olduğu için ayarlamaya gerek yok -d $'\n'. Bir satırsonu üzerinde gerçekleşen bir boş dizede kırılacak if-ifadesi, parolayı bitirmelerine izin veren şeydir.
SiegeX

FreeBSD üzerinde bash 3.x ile test ederken durumun böyle olmadığını görüyorum. 3.1.17 ile Linux üzerinde test etmek sonuçlarınızı verir. Şu anda elimde bir BSD kutusu yok ama bunu yarın, sadece kendi merakım için onaylamaya çalışacağım.
sorpigal

@Sorpigal: ilginç, ne bulduğunuzu bana bildirin. Ben tamamen taşınabilirlik
üzereyim

2
Ben aldım. FreeBSD testim, lesmana'nın gönderisinin orijinal yanlış düzenlemesinden kopyalanıp yapıştırılan koda dayanıyordu, bu önemli bir fark içeriyor: reada -d ''. Daha sonra Linux'ta yeniden denediğimde yeniden yayınlanan sürümü kullandım. -d ''Elbette atlamaya çalışırsam , FreeBSD'de aynı şekilde çalışır! Aslında burada iş yerinde gizemli bir platform büyüsü olmadığı için oldukça rahatladım.
sorpigal

17

yankıyı devre dışı bırakmak readiçin kullanabileceğiniz bash veya belirli özellikler olmadan çalışan bir çözüm içinstty

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

9

İşte @ SiegeX'in mükemmel *baskı çözümünün bir varyasyonu ve bash geri boşluk desteği eklendi; bu, kullanıcının girişini backspaceanahtarla ( deleteMac'te anahtar) düzeltmesine olanak tanır , çünkü genellikle parola istemleri tarafından desteklenir:

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

Not:

  • Geri al tuşuna basmanın neden karakter kodunu kaydettiğine gelince 0x7f: "Modern sistemlerde, geri al tuşu genellikle silme karakteriyle (ASCII veya Unicode'da 0x7f) eşlenir" https://en.wikipedia.org/wiki/Backspace
  • \b \bsoldaki karakteri silme görüntüsü vermek için gereklidir ; sadece kullanmak \bimleci sola taşır, ancak karakteri olduğu gibi bırakır ( tahribatsız geri tuşu). Bir boşluk yazdırıp tekrar geri hareket ederek, karakter silinmiş gibi görünür (teşekkürler, C'deki "geri boşluk" kaçış karakteri '\ b', beklenmeyen davranış? ).

Bir de POSIX sadece (örneğin kabuk shDebian ve Ubuntu, üzerinde shise dash), kullanmak stty -echoyaklaşımı (o yazdırır, çünkü suboptimal şey ) çünkü readyerleşik desteklemeyeceğini -sve -nseçenekler.


Teşekkürler @Dylan. Şimdiye kadar yazılan şifreden son karakteri silme kodunun basitleştirilebileceğini yeni fark ettim - güncellemeye bakın.
mklement0

3

@ Lesmana'nın cevabından biraz farklı (ama çoğunlukla benzer)

stty -echo
read password
stty echo

basitçe: yankıyı gizle işini yap yankıyı göster


Bunun neden @ lesmana'nın cevabından daha iyi olduğunu açıklayabilir misiniz ? Başka bir sttyçağrı için daha az ek yük ve yığındaki bir daha az değişkenle daha basit olduğunu görüyorum - yalnızca yankıyı ortadan kaldırıyor ve yalnızca yankıyı geri getiriyor. Bunun diğer sttyayarları altüst etmesi olası bir yol var mı ? Lesmana tüm ayarları korur.
Jeff Puckett

2

Burada, @ SiegeX'in geleneksel Bourne kabuğu ile çalışan ( +=atamaları desteklemeyen ) cevabının bir varyasyonu var .

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

Geleneksel bir Bourne kabuğu (veya POSIX uyumlu bir kabuk) da tanımaz [[ ... ]]ve readyerleşikinde -sve -nseçeneklerine sahip olmaz . Kodunuz bu nedenle dash, örneğin çalışmayacaktır . (Bu platformlarda çalışacak shaslında bashböyle OSX, olduğu gibi, basholarak çağrılan shhala en bashisms desteklerken sadece birkaç varsayılan seçenekleri değiştirir.)
mklement0

2
Geri bildiriminiz için teşekkürler, bekarlığa [geçtim ama açıkçası readbu seçeneklerden yoksunsa yapabileceğim pek bir şey yok .
üçlü

2

Her zaman Ansi kaçış karakterlerini kullanmayı severim:

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

8mmetni görünmez yapar ve 0mmetni "normal" e sıfırlar. -E, Ansi'nin kaçışını mümkün kılar.

Tek uyarı, orada bulunan metni hala kopyalayıp yapıştırabilmenizdir, bu nedenle gerçekten güvenlik istiyorsanız, muhtemelen bunu kullanmamalısınız.

Sadece siz yazarken insanların parolalarınıza bakmamasını sağlar. Daha sonra bilgisayarınızı açık bırakmayın. :)


NOT:

Yukarıdakiler, Ansi kaçış dizilerini desteklediği sürece platformdan bağımsızdır.

Ancak, başka bir Unix çözümü için, readkarakterleri tekrarlamamanızı söyleyebilirdiniz ...

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

1

Kullanıcı adı ve şifre alın

Okumayı daha net hale getirin, ancak ekranın üzerinde daha iyi bir konuma yerleştirin

#!/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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.