99bottles.sh 5.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. #!/bin/bash
  2. #
  3. # Bottles of Beer song in Bash
  4. #
  5. # A way-overcomplicated implementation of the bottles of beer song in bash.
  6. # Optional argument:
  7. #
  8. # * `--careless` - Generate the "happen to fall" version
  9. #
  10. # NOTE: This is an altered version of a "99 bottles of beer" song
  11. # Bash script by Bill Brown. The intent of the altered version is
  12. # to show the style, so the above text is preserved from [the
  13. # original][99b].
  14. #
  15. # [99b]: http://99-bottles-of-beer.net/language-bash-1831.html
  16. #
  17. standardBreakLine="Take one down and pass it around"
  18. wastefulBreakLine="If one of those bottles should happen to fall"
  19. breakLine=$([ "$1" = --careless ] \
  20. && echo $wastefulBreakLine \
  21. || echo $standardBreakLine)
  22. pred() { #get predecessor to a number
  23. case $1 in
  24. *nine) echo ${1%nine}eight;;
  25. *eight) echo ${1%eight}seven;;
  26. *seven) echo ${1%seven}six;;
  27. *six) echo ${1%six}five;;
  28. *five) echo ${1%five}four;;
  29. *four) echo ${1%four}three;;
  30. *three) echo ${1%three}two;;
  31. *two) echo ${1%two}one;;
  32. one) echo zero;;
  33. *-one) echo ${1%-one};;
  34. *one) echo ${1%one};;
  35. ten) echo nine;;
  36. eleven) echo ten;;
  37. twelve) echo eleven;;
  38. *teen) teenpred $1;;
  39. *ty) tenspred $1;;
  40. zero) echo ""; #to terminate
  41. esac
  42. }
  43. teenpred() { #predecessor of a teen
  44. case $1 in
  45. thirteen) echo twelve;;
  46. *) echo $(crunchprefix $(pred $(uncrunchprefix ${1%teen})))teen;;
  47. esac
  48. }
  49. tenspred() { #predecessor of a multiple of ten
  50. case $1 in
  51. twenty) echo nineteen;;
  52. *) echo $(crunchprefix --tens $(pred $(uncrunchprefix ${1%ty})))ty-nine;;
  53. esac
  54. }
  55. crunchprefix() {
  56. #crunch number prefix to its conventional form
  57. # such as three --> thir
  58. # option --tens multiples of ten are a bit different
  59. [ $1 = --tens ] && { tensop=true; shift; }
  60. case $1 in
  61. two) [ -n "$tensop" ] && echo twen || echo $1;;
  62. three) echo thir;;
  63. four) [ -n "$tensop" ] && echo 'for' || echo $1;;
  64. five) echo fif;;
  65. eight) [ -n "$tensop" ] && echo eigh || echo $1;;
  66. *) echo $1;;
  67. esac
  68. }
  69. uncrunchprefix() { #reverse crunchprefix
  70. case $1 in
  71. twen) echo two;;
  72. thir) echo three;;
  73. 'for') echo four;;
  74. fif) echo five;;
  75. eigh) echo eight;;
  76. *) echo $1;;
  77. esac
  78. }
  79. grammar() { #peculiarities of English grammar
  80. local oneBottle=false #can effect the following line
  81. while read line; do
  82. line="${line/one more bottles/one more bottle}"
  83. case "$line" in
  84. *"one of those bottles"*) line="$([ $oneBottle = true ] &&
  85. echo ${line/one of those bottles/that lone bottle} ||
  86. echo $line )"
  87. ;;
  88. *"one down"*) line="$([ $oneBottle = true ] &&
  89. echo ${line/one down/it down} ||
  90. echo $line )"
  91. ;;
  92. *bottles*) oneBottle=false;;
  93. *bottle*) oneBottle=true;;
  94. esac
  95. #Some say the twenties should have no hyphen
  96. line="${line/twenty-/twenty }"
  97. echo $line
  98. done
  99. }
  100. capitalize() { #fix beginning of each line
  101. while read line; do
  102. echo -n ${line:0:1} | tr '[:lower:]' '[:upper:]'
  103. echo ${line#?}
  104. done
  105. }
  106. punctuate() { #add punct to each line
  107. while read line; do
  108. case "${line}" in
  109. [Ii]f*) echo ${line},;;
  110. '') echo;;
  111. *) echo ${line}.;;
  112. esac
  113. done
  114. }
  115. verse () { #write one verse
  116. local nb=$1
  117. echo $nb bottles of beer on the wall
  118. echo $nb bottles of beer
  119. if [ $nb = zero ]; then
  120. echo Go to the store and buy some more
  121. nb=ninety-nine
  122. else
  123. echo $breakLine
  124. nb=$(pred $nb)
  125. fi
  126. echo $nb bottles of beer on the wall
  127. }
  128. poeticize() { #make it nice
  129. while read first rest; do
  130. case "$rest" in
  131. *beer*)
  132. first=${first/zero/no}
  133. local syl=$(syllables ${first% *})
  134. case $syl in #improve meter
  135. 1|2) echo $first 'more' $rest;;
  136. *) echo $first $rest;;
  137. esac
  138. ;;
  139. *) echo $first $rest
  140. esac
  141. done
  142. }
  143. syllables() { #estimate number of syls in word
  144. local n=1
  145. case $1 in
  146. eleven) n=2;; #sounds better if not considered 3
  147. *teen) n=2;;
  148. *ty) n=2;;
  149. *-*) n=3;; #don't care about more than 3
  150. esac
  151. case $1 in
  152. *seven*) let $((n = n+1));;
  153. esac
  154. echo $n
  155. }
  156. nb=ninety-nine
  157. while [ -n "$nb" ]; do
  158. verse $nb
  159. echo
  160. nb=$(pred $nb)
  161. done | poeticize | grammar | punctuate | capitalize