Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
443 views
in Technique[技术] by (71.8m points)

bash - How does this "Number to Roman" shell script work?

i'm beginning with bash, and i want to understand this example... If one of you can help me understanding the "to_roman" function, i'll be very grateful! or if you have some documentation for help, thanks!

#!/bin/bash
LIMIT=200
E_ARG_ERR=65
E_OUT_OF_RANGE=66

if [ -z "$1" ]
then
  echo "Usage: `basename $0` number-to-convert"
  exit $E_ARG_ERR
fi  

num=$1
if [ "$num" -gt $LIMIT ]
then
    echo "Out of range!"
    exit $E_OUT_OF_RANGE
fi  

to_roman ()
{
    number=$1
    factor=$2
    rchar=$3
    let "remainder = number - factor"
    while [ "$remainder" -ge 0 ]
    do
        echo -n $rchar
        let "number -= factor"
        let "remainder = number - factor"
    done  
    return $number
}

to_roman $num 100 C
num=$?
to_roman $num 90 LXXXX
num=$?
to_roman $num 50 L
num=$?
to_roman $num 40 XL
num=$?
to_roman $num 10 X
num=$?
to_roman $num 9 IX
num=$?
to_roman $num 5 V
num=$?
to_roman $num 4 IV
num=$?
to_roman $num 1 I
echo
exit
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

The to_roman () is a function definition and not part of the program itself. The actual program starts below that.

before to_roman (), the program is simply verifying your input. Did you include a parameter? If not, the first if statement will catch that.

Is the number greater than 200? If it is greater than 200, the second if will take care of that.

The heart of the program is:

to_roman $num 100 C
num=$?
to_roman $num 90 LXXXX
num=$?
to_roman $num 50 L
num=$?

The program is running the to_roman function with the three parameters. The first is the number you want to convert (or what's left of that number. The second is the factor of that number, and the third is the character to print.

The program, is using a loop. For example, if I pass in the parameters 175, 100, and C into the to_roman function, it subtracts 150 - 100, sees the results are still greater than 0, and prints out the letter C and tries again. In this case, it tries it once more, but gets the number -25. Since it's less than zero, the subroutine exits with 75. The num=$? sets number with the leftover (amount 75 in this case).

This is done for to_roman 75 90 LXXXX (which doesn't print out anything because 90 - 75 is less than zero), to_roman 75 50 L (which prints out a single L because you can subtract a single 50 from 75). The result of that last one is 25.

Here's something you can do to help you understand a shell script. First:

$ export PS4="$LINENO: "

The PS4 prompt is for debugging. The default PS4 prompt is + which isn't too useful. This changes the PS4 prompt to the line number of the shell script that is being debugged.

Now, put set -xv and set +xv around the area of the shell script your trying to debug. In this case, you probably want to put it at the beginning and ending of the script. Here's my debugging output with the number 175. See if you can follow what's going on:

$ ./roman.sh 175
LIMIT=200
3: LIMIT=200
E_ARG_ERR=65
4: E_ARG_ERR=65
E_OUT_OF_RANGE=66
5: E_OUT_OF_RANGE=66

if [ -z "$1" ]
then
  echo "Usage: `basename $0` number-to-convert"
  exit $E_ARG_ERR
fi  
7: '[' -z 175 ']'

num=$1
13: num=175
if [ "$num" -gt $LIMIT ]
then
    echo "Out of range!"
    exit $E_OUT_OF_RANGE
fi  
14: '[' 175 -gt 200 ']'

to_roman ()
{
    number=$1
    factor=$2
    rchar=$3
    let "remainder = number - factor"
    while [ "$remainder" -ge 0 ]
    do
        echo -n $rchar
        let "number -= factor"
        let "remainder = number - factor"
    done  
    return $number
}

to_roman $num 100 C
35: to_roman 175 100 C
22: number=175
23: factor=100
24: rchar=C
25: let 'remainder = number - factor'
26: '[' 75 -ge 0 ']'
28: echo -n C
C29: let 'number -= factor'
30: let 'remainder = number - factor'
26: '[' -25 -ge 0 ']'
32: return 75
num=$?
36: num=75
to_roman $num 90 LXXXX
37: to_roman 75 90 LXXXX
22: number=75
23: factor=90
24: rchar=LXXXX
25: let 'remainder = number - factor'
26: '[' -15 -ge 0 ']'
32: return 75
num=$?
38: num=75
to_roman $num 50 L
39: to_roman 75 50 L
22: number=75
23: factor=50
24: rchar=L
25: let 'remainder = number - factor'
26: '[' 25 -ge 0 ']'
28: echo -n L
L29: let 'number -= factor'
30: let 'remainder = number - factor'
26: '[' -25 -ge 0 ']'
32: return 25
num=$?
40: num=25
to_roman $num 40 XL
41: to_roman 25 40 XL
22: number=25
23: factor=40
24: rchar=XL
25: let 'remainder = number - factor'
26: '[' -15 -ge 0 ']'
32: return 25
num=$?
42: num=25
to_roman $num 10 X
43: to_roman 25 10 X
22: number=25
23: factor=10
24: rchar=X
25: let 'remainder = number - factor'
26: '[' 15 -ge 0 ']'
28: echo -n X
X29: let 'number -= factor'
30: let 'remainder = number - factor'
26: '[' 5 -ge 0 ']'
28: echo -n X
X29: let 'number -= factor'
30: let 'remainder = number - factor'
26: '[' -5 -ge 0 ']'
32: return 5
num=$?
44: num=5
to_roman $num 9 IX
45: to_roman 5 9 IX
22: number=5
23: factor=9
24: rchar=IX
25: let 'remainder = number - factor'
26: '[' -4 -ge 0 ']'
32: return 5
num=$?
46: num=5
to_roman $num 5 V
47: to_roman 5 5 V
22: number=5
23: factor=5
24: rchar=V
25: let 'remainder = number - factor'
26: '[' 0 -ge 0 ']'
28: echo -n V
V29: let 'number -= factor'
30: let 'remainder = number - factor'
26: '[' -5 -ge 0 ']'
32: return 0
num=$?
48: num=0
to_roman $num 4 IV
49: to_roman 0 4 IV
22: number=0
23: factor=4
24: rchar=IV
25: let 'remainder = number - factor'
26: '[' -4 -ge 0 ']'
32: return 0
num=$?
50: num=0
to_roman $num 1 I
51: to_roman 0 1 I
22: number=0
23: factor=1
24: rchar=I
25: let 'remainder = number - factor'
26: '[' -1 -ge 0 ']'
32: return 0
echo
52: echo

set -xv
53: set -xv
exit
54: exit

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...