99bottles.sh 4.6KB

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