So I was doing the Bash exercise ‘bob.sh’. While ‘Test 21-multiple line question’ is passing fine on my local machine, but not exercism. The code is copy-pasted from my local pc.
Can I copy-paste my code in here so any one can have a look at it?
This is the bash version on my Fedora 38 machine: GNU bash, version 5.2.15(1)-release (x86_64-pc-linux-gnu)
I’m new here but already learning a LOT and enjoying the exercises. Thanks a lot!
FAILED
Test 21
multiple line question
CODE RUN
run bash bob.sh $'\nDoes this cryogenic chamber make me look fat?\nNo'
assert_success
assert_output "Whatever."
TEST FAILURE
(from function `assert_output' in file bats-extra.bash, line 394,
in test file bob.bats, line 150)
`assert_output "Whatever."' failed
-- output differs --
expected : Whatever.
actual : Fine. Be that way!
--
Here’s the same code I’m using on my machine:
#!/usr/bin/env bash
declare -A RESPONSE_HASH=([sure]="Sure." [chill_out]="Whoa, chill out!" [calm_down]="Calm down, I know what I'm doing!" [fine]="Fine. Be that way!" [whatever]="Whatever.")
RESPONSE=
WEIGHT=0
read -r STATEMENT <<< "$1"
read -ra ARRAY <<< "$1"
INDEX=${#STATEMENT}
if [[ ${#STATEMENT} -ne 0 ]]; then
for ((i=0; i<$((INDEX-1)); i++)) {
if [[ ${STATEMENT:i:1} =~ [[:lower:]] ]]; then
if [[ ${STATEMENT:i+1:1} =~ [[:punct:][:digit:][:space:]] ]]; then
WEIGHT=2
break
fi
WEIGHT=4
elif [[ ${STATEMENT:i:1} =~ [[:upper:]] ]]; then
if [[ ${STATEMENT:i+1:1} =~ [[:lower:]] ]]; then
WEIGHT=4
break
fi
WEIGHT=7
elif [[ ${STATEMENT:i:1} =~ [[:punct:][:digit:][:space:]] ]]; then
if [[ $WEIGHT != 0 ]]; then
WEIGHT=$WEIGHT
else
WEIGHT=2
fi
fi
}
fi
if [[ ${STATEMENT: -1:1} == '?' ]]; then
WEIGHT=$((WEIGHT+1))
fi
case $WEIGHT in
0)
RESPONSE="${RESPONSE_HASH[fine]}"
;;
1|3|5)
RESPONSE="${RESPONSE_HASH[sure]}"
;;
2|4|6)
RESPONSE="${RESPONSE_HASH[whatever]}"
;;
7)
RESPONSE="${RESPONSE_HASH[chill_out]}"
;;
8)
RESPONSE="${RESPONSE_HASH[calm_down]}"
;;
esac
echo "$RESPONSE"
user@pc:~/programming/exercism.org/bash$ ./bob.sh '\nDoes this cryogenic chamber make me look fat?\nNo'
Whatever.
Note, '\n' and $'\n' are not the same thing. The former is a literal \ char and a literal n char. The latter is a newline char. bash has a special form of $'..' quoting which expands escape sequences. Your local test and the bats unit test differ.
I think I’m getting close on this one. I have one more question regarding Test 23.
Shouldn’t the answer for this is Whatever. since the sentence actually ended with a space and not a question mark? I pasted my new code below:
FAILED
Test 23
ending with whitespace
![](https://assets.exercism.org/assets/icons/chevron-down-5ae28e42ee217bae38f4eb1c119cafd0301dd5f6.svg)
### CODE RUN
\```
run bash bob.sh 'Okay if like my spacebar quite a bit? '
assert_success
assert_output "Sure."
\```
### TEST FAILURE
(from function `assert_output' in file bats-extra.bash, line 394, in test file bob.bats, line 164) `assert_output "Sure."' failed -- output differs -- expected : Sure. actual : Whatever. --
#!/usr/bin/env bash
main () {
declare -A RESPONSE_HASH=([sure]="Sure."
[chill_out]="Whoa, chill out!"
[calm_down]="Calm down, I know what I'm doing!"
[fine]="Fine. Be that way!"
[whatever]="Whatever.")
RESPONSE=
WEIGHT=0x00
read -r STATEMENT <<< "$1"
read -ra ARRAY <<< "$1"
INDEX=${#1}
if [[ ${#1} -ne 0 ]]; then
for ((i=0; i<$((INDEX-1)); i++)) {
if [[ ${1:i:1} =~ [[:space:]] && ${1: i+1:1} =~ [[:space:]] ]]; then
#echo "before: space-space $WEIGHT"
#WEIGHT=$(printf "0x%02x" "0x00")
WEIGHT=$((WEIGHT | 0x00))
#echo "after: space-space ${1:i:1} $WEIGHT"
elif [[ ${1:i:1} =~ [[:space:]] && ${1: i+1:1} =~ [^[:space:]] ]]; then
#echo "before: space-not-space ${1:i:1} ${1: i+1:1} $WEIGHT"
WEIGHT=$((WEIGHT | 0x02))
#echo "after: space-not-space $WEIGHT"
elif [[ ${1:i:1} =~ [[:digit:][:punct:]] && ${1: i+1:1} =~ [[:digit:][:punct:]] ]]; then
#echo "before: digit-punct $WEIGHT"
#WEIGHT=$(printf "0x%02x" "0x04")
WEIGHT=$((WEIGHT | 0x04))
#echo "after: digit-punct $WEIGHT"
#WEIGHT=$((WEIGHT | 0x04))
#elif [[ ${1:i:1} =~ [[:digit:][:punct:]] && ${1: i+1:1} =~ [^[:digit:][:punct:]] ]]; then
# WEIGHT=$((WEIGHT | 0x08))
elif [[ ${1:i:1} =~ [[:lower:]] ]]; then
#echo "before: lower $WEIGHT"
WEIGHT=$((WEIGHT | 0x08))
#echo "after: lower $WEIGHT"
elif [[ ${1:i:1} =~ [[:upper:]] ]]; then
#echo "before: upper ${1:i:1} - $WEIGHT"
WEIGHT=$((WEIGHT | 0x10))
#echo "after: upper ${1:i:1} - $WEIGHT"
fi
}
WEIGHT=$(printf "0x%02x" "$WEIGHT")
if [[ ${1: -1:1} == '?' ]]; then
WEIGHT=$(printf "0x%02x" "$((WEIGHT + 0x01))")
fi
fi
#echo "weight: $WEIGHT -- ${#1}"
case $WEIGHT in
0x05|0x07|0x07|0x09|0x0d|0x1b|0x1f)
RESPONSE="${RESPONSE_HASH[sure]}"
;;
0x00)
RESPONSE="${RESPONSE_HASH[fine]}"
;;
0x06|0x0e|0x1a)
RESPONSE="${RESPONSE_HASH[whatever]}"
;;
0x10|0x12|0x16)
RESPONSE="${RESPONSE_HASH[chill_out]}"
;;
0x13)
RESPONSE="${RESPONSE_HASH[calm_down]}"
;;
esac
echo "$RESPONSE"
}
main "$@"
I’ve finally cracked it! Wow, this is not an easy task, for me at least. I implemented my solution using the native features available to bash and did not use any external tools. I’m not sure if that is the intention here.
How can I mark this as solved?
#!/usr/bin/env bash
shopt -s extglob
main () {
declare -A RESPONSE_HASH=([sure]="Sure."
[chill_out]="Whoa, chill out!"
[calm_down]="Calm down, I know what I'm doing!"
[fine]="Fine. Be that way!"
[whatever]="Whatever.")
RESPONSE=
WEIGHT=0x00
PARAM="$1"
PARAM=$(printf '%s\n' "${PARAM%%+([[:space:]])}")
PARAM=$(printf '%s\n' "${PARAM##+([[:space:]])}")
if [[ ${#1} -ne 0 ]]; then
for ((i=0; i<${#1}-1; i++)) {
if [[ ${PARAM:i:1} =~ [[:space:]] && ${PARAM: i+1:1} =~ [[:space:]] ]]; then
WEIGHT=$((WEIGHT | 0x00))
elif [[ ${PARAM:i:1} =~ [[:space:]] && ${PARAM: i+1:1} =~ [^[:space:]] ]]; then
WEIGHT=$((WEIGHT | 0x02))
elif [[ ${PARAM:i:1} =~ [[:digit:][:punct:]] && ${PARAM: i+1:1} =~ [[:digit:][:punct:]] ]]; then
WEIGHT=$((WEIGHT | 0x04))
elif [[ ${PARAM:i:1} =~ [[:lower:]] ]]; then
WEIGHT=$((WEIGHT | 0x08))
elif [[ ${PARAM:i:1} =~ [[:upper:]] ]]; then
WEIGHT=$((WEIGHT | 0x10))
fi
}
WEIGHT=$(printf "0x%02x" "$WEIGHT")
if [[ ${PARAM: -1:1} == '?' ]]; then
WEIGHT=$(printf "0x%02x" "$((WEIGHT + 0x01))")
fi
fi
#echo "weight: $WEIGHT -- ${#PARAM}"
case $WEIGHT in
0x05|0x07|0x09|0x0d|0x1b|0x1f)
RESPONSE="${RESPONSE_HASH[sure]}"
;;
0x00)
RESPONSE="${RESPONSE_HASH[fine]}"
;;
0x06|0x0c|0x0e|0x18|0x1a)
RESPONSE="${RESPONSE_HASH[whatever]}"
;;
0x10|0x12|0x16)
RESPONSE="${RESPONSE_HASH[chill_out]}"
;;
0x13)
RESPONSE="${RESPONSE_HASH[calm_down]}"
;;
esac
echo "$RESPONSE"
}
main "$@"
This is an awesome website, I should have discovered this earlier!
This would account for the $'\nDoes this cryogenic chamber make me look fat?\nNo' test failure: your code read the (empty) line before the first newline and returned the “silence” response.
(declare -p varname is a very handy way to dump the exact contents of a variable.)
Get out of the habit of using ALLCAPS variable names, leave those as reserved by the shell. One day you’ll write PATH=something and then wonderwhy your script is broken.
If you’re using ALLCAPS to indicate a constant, use the readonly or declare -r builtins to let the shell know too.