무작위 비밀번호를 생성하고("플래그"가 올바른 경우) 이를 txt 파일에 저장하는 bash 스크립트를 만들었습니다. 단일 명령으로 실행할 수 있도록 스크립트 경로에 별칭을 추가했습니다. 나는 그것을 "랜드"라고 부른다.
내가 이미 가지고 있는 것은 효과가 있지만 전혀 우아하지 않습니다. 첫째, 플래그가 지금처럼 고정되어 있는 것보다 어떤 순서로든 포함될 수 있었으면 좋겠다. 현재는 2개만 가지고 있습니다. -p는 "보안 비밀번호"를 의미하고 -s는 "저장"을 의미합니다. "username"을 나타내기 위해 하나 이상의 -u를 추가하고 싶지만 현재 코드 상태가 마음에 들지 않기 때문에 지금은 보류하고 있습니다.
다음과 같이 명령을 실행하고 싶습니다.
rand -FLAGS_IN_ANY_ORDER -NUMBER -FILE_NAME
다음은 코드의 현재 버전입니다.
#!/bin/bash
num=$#
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
if [[ "$1" = "-p" ]]; then
cat /dev/urandom \
| tr -dc A-Za-z0-9.-@ \
| head -c $2 ; echo
elif [[ "$1" = "-ps" ]] && [[ "$3" = * ]]; then
cat /dev/urandom \
| tr -dc A-Za-z0-9.-@ \
| head -c $2 > $DIR/$3.txt && echo >> $DIR/$3.txt
cat $DIR/$3.txt
elif [[ "$1" = "-s" ]] && [[ "$3" = * ]]; then
cat /dev/urandom \
| tr -dc A-Za-z0-9 \
| head -c $2 > $DIR/$3.txt && echo >> $DIR/$3.txt
cat $DIR/$3.txt
else
cat /dev/urandom \
| tr -dc A-Za-z0-9 \
| head -c $1 ; echo
fi
이상적으로는 가능한 적은 코드 줄을 원하지만 if
모든 명령문이 그런 것은 아닙니다.
getopts
나는 이것을 시도했지만 case
단순히 작동시킬 수 없습니다. 이것은 내가 지금까지 가지고 있는 코드 중 깨지지 않은 유일한 버전입니다.
하지만 변호하자면 저는 UNIX 계열 시스템이 처음이고 몇 주 전부터 bash 스크립트를 작성하기 시작했습니다.
이 문제를 어떻게 해결하시겠습니까?
답변1
다음 스크립트는 귀하의 것보다 길지만, usage
이를 사용하여 도움말 메시지를 인쇄하는 기능을 추가하고(오류 조건이 감지되면 오류 메시지를 인쇄하는 데에도 사용됨) 설명하기 위해 많은 주석을 추가했기 때문에 모든 추가 길이가 발생했습니다. 어떤 코드를 수행하며 그 이유는 무엇입니까?
옵션을 구문 분석하고 작업을 수행하는 코드는 훨씬 더 짧고 간단하며 확장하기 쉽습니다(예: 현재 옵션을 사용 -u username
하지만 사용 방법을 언급하지 않았기 때문에 해당 옵션으로 아무 작업도 수행하지 않습니다). 모든 특별한 경우 처리가 제거되고, 수행할 작업과 수행 방법에 대한 "결정"은 if/then 테스트가 뒤따르는 Case 문에서 이루어집니다.
출력 디렉터리를 지정할 수 있도록 옵션 도 추가했습니다 ... 하지만 출력 파일에 문자 가 -d
포함되어 있는지 확인하는 코드도 추가했기 때문에 다른 옵션을 추가하는 방법에 대한 예 외에는 중복됩니다. /
앞에 추가하기만 하면 됩니다 $outdir
(이름에서 이름을 바꾸십시오. 스크립트에서는 변수 이름을 소문자로 사용하고 표준 유틸리티에서는 대문자를 유지하는 것이 좋습니다). 즉, 또는 를 $DIR
사용할 수 있습니다 .-f /path/to/file
-d /path/to -f file
그런데 이 스크립트에 대한 전체 경로가 포함된 별칭을 생성하지 말고 이를 홈 디렉터리에 넣거나 하위 디렉터리를 생성하여 /usr/local/bin
$PATH에 추가하는 것이 좋습니다. 그런 다음 거기에서 원하는 만큼의 사용자 정의 스크립트를 작성하고 저장할 수 있습니다.bin/
~/bin
#!/bin/bash
usage() {
# this function prints a usage summary, optionally printing an error message
local ec=0
if [ $# -ge 2 ] ; then
# if printing an error message, the first arg is the exit code, and
# all remaining args are the message.
ec="$1" ; shift
printf "%s\n\n" "$*" >&2
fi
cat <<EOF
Usage:
$(basename $0) [-p | -s file | -u <user> | -d <dir> ] <[-l] length>
Generates a random password of specified length, containing only
alpha-numeric characters.
Required arguments:
-l <length> Length of password. Just the length without '-l' also works.
Options:
-p Allow some punctuation characters in password.
-s <file> Save output to filename.
-d <dir> Output directory for the save file
-u <user> Username. At present this does nothing.
-h This help message.
EOF
exit $ec
}
# Initialise variables
length=''
file=''
username=''
pattern='A-Za-z0-9'
outdir=$(dirname "$0")
# -s, -l, -u and -d require an arg. -h and -p don't. The leading ':' in
# the getopts string enables 'silent' error mode (i.e. we handle
# any errors ourselves)
while getopts ':hps:l:u:d:' opt; do
case "$opt" in
p) pattern='A-Za-z0-9.-@' ;;
s) file="$OPTARG" ;;
l) length="$OPTARG" ;;
u) username="$OPTARG" ;;
d) outdir="$OPTARG" ;;
h) usage ;;
:) usage 1 "-$OPTARG requires an argument" ;;
?) usage 1 "Unknown option '$opt'" ;;
esac
done
shift $((OPTIND -1))
# Length can be specified as either `-l nnn` or just `nnn` on the cmd line
# this code exits with an error message if no length is specified.
#
# It would probably be better to give length a default value instead.
# Just change `length=''` under the Initialise variables comment above
# to whatever you want as the default, and then delete the '[ -z "$1" ]'
# line below. Remember to update the usage message - documentation should
# always match what the code does.
if [ -z "$length" ] ; then
[ -z "$1" ] && usage 1 "Length option is required"
length="$1"
shift
fi
# if there are any remaining args on the line, we don't know what to do
# with them, so exit with an error message.
[ -n "$*" ] && usage 1 "Unknown arguments: '$*'"
password=$(cat /dev/urandom | tr -dc "$pattern" | head -c "$length")
# I don't know why you want an extra newline in the output, but do it anyway.
printf "$password\n\n"
if [ -n "$file" ] ; then
# if $file doesn't have a /, pre-pend "$outdir"
[[ $file =~ '/' ]] || file="$outdir/$file"
printf "$password\n\n" > "$file"
fi
그런데 이미 많은 비밀번호 생성 프로그램이 존재합니다. 예를 들어보편적인 뿌리그리고 makepasswd
.
저는 일부 단어를 무작위로 선택 하고 이를 무작위로 생성된 1-3자리 숫자 및/또는 구두점과 연결하는 pwgen
나만의 비밀번호 생성기를 작성하기 전까지 16자리 이상의 비밀번호를 생성 했습니다 . 모두 소문자이므로 내 스크립트는 일부 문자를 무작위로 대문자로 표시합니다. 그 결과 길지만 기억하기 쉬운 비밀번호가 생성됩니다. 임의의 숫자, 구두점 및 대문자는 무차별 대입 공격에 대한 검색 공간을 늘리고 단어 사전의 예측 가능성으로 인해 비밀번호의 강도가 손상되지 않도록 하는 데 도움이 됩니다./usr/share/dict/words
/usr/share/dict/words
예를 들어
$ random-password.sh
31 surVeying % deRAngement 6 ratiocinations 51 sunDowns
$ printf '%s' '31 surVeying % deRAngement 6 ratiocinations 51 sunDowns' | wc -c
55
비밀번호 길이는 복잡성보다 훨씬 더 중요합니다. 길이가 10자 미만인 비밀번호는 최신 하드웨어를 사용하면 매우 짧은 시간에 해독될 수 있습니다(<= 7자는 1초 이하, 8자는 몇 시간, 10자는 몇 달이 소요됨). ) 문자). 현재 기술을 사용하면 55자 비밀번호는 우주가 존재하는 동안 사실상 해독할 수 없습니다(따라서 최소 10년 동안은 안전해야 합니다).
문제는 비밀번호가 길수록 사람들이 비밀번호를 기억하기 쉬워야 한다는 것입니다. 나는 비밀번호의 시작 부분만 기억하면 되고, 비밀번호를 몇 번 입력하면 의미 없는 문구의 다음 숫자와 단어가 자동으로 연결(따라서 기억)된다는 것을 알게 되었습니다.
답변2
이것이 제가 일반적으로 옵션을 수행하는 방법이지만 이로 인해 스크립트가 더 길어질 것 같습니다... 하지만 순서에 관계없이 옵션을 허용합니다.
while (( $# )); do
case $1 in
-n)
shift
number=$1
;;
-f)
shift
file_name=$1
;;
-p)
shift
password=$1
run=pass
;;
-s)
run=save
;;
-u)
shift
username=$1
;;
*)
thing=$1
save=what
;;
shift
esac
done
case $save in
save)
cat /dev/urandom \
| tr -dc A-Za-z0-9.-@ \
| head -c "$number" > "${DIR}/${file_name}.txt" && echo >> "${DIR}/${file_name}.txt"
cat "${DIR}/${file_name}.txt"
;;
pass)
cat /dev/urandom \
| tr -dc A-Za-z0-9.-@ \
| head -c "$number" ; echo
;;
*)
cat /dev/urandom \
| tr -dc A-Za-z0-9 \
| head -c "$thing" ; echo
;;
esac
while
옵션이 있는 한 루프가 실행됩니다. shift
전달한 각 인수를 반복하고 Case 문을 통해 실행하여 올바르게 처리할 수 있도록 다음 옵션으로 이동하세요.
답변3
다음은 스크립트의 변형입니다.
#!/bin/bash
opt_l=8 # password length is 8 by default
opt_o=/dev/stdout # write to standard output by default
opt_s=0 # insecure password by default
opt_u= # no default username
while getopts 'l:o:su:' opt; do
case "$opt" in
l) opt_l=$OPTARG ;;
o) opt_o=$OPTARG ;;
s) opt_s=1 ;;
u) opt_u=$OPTARG ;;
*) echo 'Error parsing options' >&2
exit 1
esac
done
args=( "$opt_l" 1 )
if (( opt_s )); then
args=( -s "${args[@]}" )
fi
if [ -n "$opt_u" ]; then
printf '%s: %s\n' "$opt_u" "$( pwgen "${args[@]}" )" >"$opt_o"
else
pwgen "${args[@]}" >"$opt_o"
fi
표준 도구 사용과 더 일관성이 있도록 일부 플래그의 이름을 변경했습니다. 지원되지 않는 플래그가 발견되면 오류 메시지를 인쇄하는 대신 사용자에게 일부 사용 정보를 출력할 수 있습니다.
이곳에서 주로 getopts
사용됩니다. 사용 중인 옵션에 대한 문자열로 사양을 사용합니다. 문자열에서 :
앞의 옵션 문자가 인수를 취함을 나타냅니다(다른 옵션은 부울 값임).
while
루프 에서 플래그가 인수를 취하는 경우 $opt
will은 옵션이고 will은 옵션 인수입니다.$OPTARG
이는 일반적 shift "$(( OPTIND - 1 ))"
으로 루프 후에도 수행되지만 스크립트는 옵션과 해당 인수를 제외하고 명령줄에서 다른 피연산자를 허용하지 않으므로 필요하지 않습니다. 이렇게 하면 추가 피연산자를 다음 shift
과 같이 사용할 수 있습니다 .$1
$2
이 스크립트를 다음과 같이 사용할 수 있습니다.
$ ./script.sh -l 4 # generates password of length 4 in the terminal
$ ./script.sh -l 4 -o file # generates password of length 4 and saves to "file"
$ ./script.sh -u bob # generates password of length 8, prepends with username "bob"
$ ./script.sh -s -u bob # generates more random password of length 8, prepends with username "bob"
-s -u bob
-ubob -s
및 -subob
, 및 와 동일합니다 -u alice -s -u bob
(후자의 옵션이 이전 옵션보다 우선합니다).
pwgen
이를 제거하고 다른 비밀번호 생성기를 사용하는 것은 매우 쉽습니다. 이를 단순화하기 위해 비밀번호 생성기를 자체 기능에 넣을 수 있습니다. 즉, 생성기를 교체할 때 기본 스크립트를 수정할 필요가 없습니다.
#!/bin/bash
passgen () {
local args=( "$opt_l" 1 )
if (( opt_s )); then
args=( -s "${args[@]}" )
fi
pwgen "${args[@]}"
}
opt_l=8 # password length is 8 by default
opt_o=/dev/stdout # write to standard output by default
opt_s=0 # insecure password by default
opt_u= # no default username
while getopts 'l:o:su:' opt; do
case "$opt" in
l) opt_l=$OPTARG ;;
o) opt_o=$OPTARG ;;
s) opt_s=1 ;;
u) opt_u=$OPTARG ;;
*) echo 'Error parsing options' >&2
exit 1
esac
done
if [ -n "$opt_u" ]; then
printf '%s: %s\n' "$opt_u" "$( passgen )" >"$opt_o"
else
passgen >"$opt_o"
fi
예를 들어, 다음은 생성기입니다.
passgen () {
local source=/dev/urandom
local chars='A-Za-z0-9'
if (( opt_s )); then
chars="$chars"'.-@'
fi
tr -dc "$chars" <"$source" | head -c "$opt_l"
}
...다음은 단어를 사용하여 암호를 생성합니다 /usr/share/dict/words
(단어 수는 -l
옵션에서 가져옴). 이 옵션을 사용 하면 -s
마지막 단어 대신 끝에 임의의 숫자가 추가됩니다.
passgen () {
local dict=/usr/share/dict/words
local numwords=$opt_l
if (( opt_s )); then
numwords=$(( numwords - 1 ))
fi
{
shuf -n "$numwords" "$dict"
if (( opt_s )); then
printf '%d\n' "$RANDOM"
fi
} | tr '\n' ' ' | sed 's/ $//'
}
마지막 passgen
기능을 실행하려면 다음 명령을 실행하세요.
./script.sh -s -u bob -l 3
다음과 같은 것을 생성할 수 있습니다.
bob: cassis befluster 22625