需要明确的是,您所询问的部分不是您会使用 bash 或任何其他 shell 的东西,所以如果您想学习在 UNIX 环境中做事的正确方法:shell 是创建/销毁文件和进程以及对工具的调用排序的环境。如果你想使用强制性的 UNIX 工具(即每个 UNIX 机器上存在的工具)来做这样的事情,那么你会使用 awk,而不是 shell。唯一的 shell 部分是调用 awk。
鉴于此,如果您想在“bash”中编写一个hangman 程序,这是一种可以在每个 UNIX 系统上使用任何 shell 中的任何 awk 来完成提示/猜测部分的方法:
$ cat tst.awk
BEGIN {
secret = word
gsub(/./,"_",secret)
print "\nOutcome:", secret
printf "guess? "
}
{
guess = $0
while ( pos=index(word,guess) ) {
secret = substr(secret,1,pos-1) guess substr(secret,pos+1)
word = substr(word,1,pos-1) "_" substr(word,pos+1)
}
print "\nOutcome:", secret
if (word ~ /^_*$/) {
exit
}
printf "guess? "
}
现在 bash(或任何其他 shell)部分将是:
$ awk -v word='abcdef' -f tst.awk
Outcome: ______
guess? a
Outcome: a_____
guess? e
Outcome: a___e_
guess? d
Outcome: a__de_
guess? f
Outcome: a__def
guess? b
Outcome: ab_def
guess? c
Outcome: abcdef
我决定实现一个完整的 hangman shell 脚本,它会生成 5 个或更多字母的单词供你猜测,因为玩起来很有趣,所以你开始吧:
$ cat ./hangman.sh
#!/usr/bin/env bash
declare -a words
trap 'printf "\nwords used:\n"; printf "%s\n" "${words[@]}"; exit' 0
prtwords() {
local dfltwordfile='/usr/share/dict/words'
{
if [[ -s "$dfltwordfile" ]]; then
cat "$dfltwordfile"
else
curl -s 'https://svnweb.freebsd.org/csrg/share/dict/words?view=co&content-type=text/plain'
fi
} |
tr 'A-Z' 'a-z' |
grep -E '.{5}' |
shuf
}
guesschars() {
awk -v word="$1" '
BEGIN {
secret = origWord = word
gsub(/./,"_",secret)
print "\nOutcome:", secret
printf "guess? "
maxFailures = 6
}
NF {
guess = substr($1,1,1)
isFailure = 1
while ( pos=index(word,guess) ) {
isFailure = 0
secret = substr(secret,1,pos-1) guess substr(secret,pos+1)
word = substr(word,1,pos-1) "_" substr(word,pos+1)
}
numFailures += isFailure
print "\nOutcome:", secret
if ( (word ~ /^_*$/) || (numFailures == maxFailures) ) {
print "The word was", origWord
exit
}
printf "guess? "
}
'
}
# See https://stackoverflow.com/a/41652573/1745001 for rationale on
# the file descriptor manipulation below.
exec 3</dev/tty || exec 3<&0 ## make FD 3 point to the TTY or stdin (as fallback)
echo 'Hit interrupt to stop' >&2
while IFS= read -r word; do ## |- loop over lines read from FD 0
words+=( "$word" )
guesschars "$word" <&3 ## |- run guesschars with its stdin copied from FD 3
echo '#####' >&2
done < <(prtwords) ## \-> ...while the loop is run with prtwords output on FD 0
exec 3<&- ## close FD 3 when done.
.
$ ./hangman.sh
Hit interrupt to stop
Outcome: __________
guess? a
Outcome: _______a__
guess? e
Outcome: _e__e__a_e
guess? s
Outcome: _e__e__a_e
guess? t
Outcome: _e__e__ate
guess? r
Outcome: _e_re__ate
guess? c
Outcome: _e_rec_ate
guess? d
Outcome: de_rec_ate
guess? p
Outcome: deprec_ate
guess? i
Outcome: depreciate
The word was depreciate
#####
Outcome: ______
guess?
words used:
depreciate
enrico