99bottles.sh 4.2KB

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