📄 arrays.html
字号:
107 echo '- - in versions of Bash newer than version 2.05b - -' 108 109 # MSZ: Sorry about any earlier confusion folks. 110 111 exit 0</PRE></TD></TR></TABLE><HR></DIV><P>--</P><P>Arrays permit deploying old familiar algorithms as shell scripts. Whether this is necessarily a good idea is left to the reader to decide.</P><P><ANAME="BUBBLESORT"></A></P><DIVCLASS="EXAMPLE"><HR><ANAME="BUBBLE"></A><P><B>Example 26-11. The Bubble Sort</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING"> 1 #!/bin/bash 2 # bubble.sh: Bubble sort, of sorts. 3 4 # Recall the algorithm for a bubble sort. In this particular version... 5 6 # With each successive pass through the array to be sorted, 7 #+ compare two adjacent elements, and swap them if out of order. 8 # At the end of the first pass, the "heaviest" element has sunk to bottom. 9 # At the end of the second pass, the next "heaviest" one has sunk next to bottom. 10 # And so forth. 11 # This means that each successive pass needs to traverse less of the array. 12 # You will therefore notice a speeding up in the printing of the later passes. 13 14 15 exchange() 16 { 17 # Swaps two members of the array. 18 local temp=${Countries[$1]} # Temporary storage 19 #+ for element getting swapped out. 20 Countries[$1]=${Countries[$2]} 21 Countries[$2]=$temp 22 23 return 24 } 25 26 declare -a Countries # Declare array, 27 #+ optional here since it's initialized below. 28 29 # Is it permissable to split an array variable over multiple lines 30 #+ using an escape (\)? 31 # Yes. 32 33 Countries=(Netherlands Ukraine Zaire Turkey Russia Yemen Syria \ 34 Brazil Argentina Nicaragua Japan Mexico Venezuela Greece England \ 35 Israel Peru Canada Oman Denmark Wales France Kenya \ 36 Xanadu Qatar Liechtenstein Hungary) 37 38 # "Xanadu" is the mythical place where, according to Coleridge, 39 #+ Kubla Khan did a pleasure dome decree. 40 41 42 clear # Clear the screen to start with. 43 44 echo "0: ${Countries[*]}" # List entire array at pass 0. 45 46 number_of_elements=${#Countries[@]} 47 let "comparisons = $number_of_elements - 1" 48 49 count=1 # Pass number. 50 51 while [ "$comparisons" -gt 0 ] # Beginning of outer loop 52 do 53 54 index=0 # Reset index to start of array after each pass. 55 56 while [ "$index" -lt "$comparisons" ] # Beginning of inner loop 57 do 58 if [ ${Countries[$index]} \> ${Countries[`expr $index + 1`]} ] 59 # If out of order... 60 # Recalling that \> is ASCII comparison operator 61 #+ within single brackets. 62 63 # if [[ ${Countries[$index]} > ${Countries[`expr $index + 1`]} ]] 64 #+ also works. 65 then 66 exchange $index `expr $index + 1` # Swap. 67 fi 68 let "index += 1" # Or, index+=1 on Bash, ver. 3.1 or newer. 69 done # End of inner loop 70 71 # ---------------------------------------------------------------------- 72 # Paulo Marcel Coelho Aragao suggests for-loops as a simpler altenative. 73 # 74 # for (( last = $number_of_elements - 1 ; last > 0 ; last-- )) 75 ## Fix by C.Y. Hunt ^ (Thanks!) 76 # do 77 # for (( i = 0 ; i < last ; i++ )) 78 # do 79 # [[ "${Countries[$i]}" > "${Countries[$((i+1))]}" ]] \ 80 # && exchange $i $((i+1)) 81 # done 82 # done 83 # ---------------------------------------------------------------------- 84 85 86 let "comparisons -= 1" # Since "heaviest" element bubbles to bottom, 87 #+ we need do one less comparison each pass. 88 89 echo 90 echo "$count: ${Countries[@]}" # Print resultant array at end of each pass. 91 echo 92 let "count += 1" # Increment pass count. 93 94 done # End of outer loop 95 # All done. 96 97 exit 0</PRE></TD></TR></TABLE><HR></DIV><P>--</P><P><ANAME="ARRAYNEST"></A></P><P>Is it possible to nest arrays within arrays?</P><P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING"> 1 #!/bin/bash 2 # "Nested" array. 3 4 # Michael Zick provided this example, 5 #+ with corrections and clarifications by William Park. 6 7 AnArray=( $(ls --inode --ignore-backups --almost-all \ 8 --directory --full-time --color=none --time=status \ 9 --sort=time -l ${PWD} ) ) # Commands and options. 10 11 # Spaces are significant . . . and don't quote anything in the above. 12 13 SubArray=( ${AnArray[@]:11:1} ${AnArray[@]:6:5} ) 14 # This array has six elements: 15 #+ SubArray=( [0]=${AnArray[11]} [1]=${AnArray[6]} [2]=${AnArray[7]} 16 # [3]=${AnArray[8]} [4]=${AnArray[9]} [5]=${AnArray[10]} ) 17 # 18 # Arrays in Bash are (circularly) linked lists 19 #+ of type string (char *). 20 # So, this isn't actually a nested array, 21 #+ but it's functionally similar. 22 23 echo "Current directory and date of last status change:" 24 echo "${SubArray[@]}" 25 26 exit 0</PRE></TD></TR></TABLE></P><P>--</P><P>Embedded arrays in combination with <AHREF="bash2.html#VARREFNEW">indirect references</A> create some fascinating possibilities</P><P><ANAME="ARRAYINDIR"></A></P><DIVCLASS="EXAMPLE"><HR><ANAME="EMBARR"></A><P><B>Example 26-12. Embedded arrays and indirect references</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING"> 1 #!/bin/bash 2 # embedded-arrays.sh 3 # Embedded arrays and indirect references. 4 5 # This script by Dennis Leeuw. 6 # Used with permission. 7 # Modified by document author. 8 9 10 ARRAY1=( 11 VAR1_1=value11 12 VAR1_2=value12 13 VAR1_3=value13 14 ) 15 16 ARRAY2=( 17 VARIABLE="test" 18 STRING="VAR1=value1 VAR2=value2 VAR3=value3" 19 ARRAY21=${ARRAY1[*]} 20 ) # Embed ARRAY1 within this second array. 21 22 function print () { 23 OLD_IFS="$IFS" 24 IFS=$'\n' # To print each array element 25 #+ on a separate line. 26 TEST1="ARRAY2[*]" 27 local ${!TEST1} # See what happens if you delete this line. 28 # Indirect reference. 29 # This makes the components of $TEST1 30 #+ accessible to this function. 31 32 33 # Let's see what we've got so far. 34 echo 35 echo "\$TEST1 = $TEST1" # Just the name of the variable. 36 echo; echo 37 echo "{\$TEST1} = ${!TEST1}" # Contents of the variable. 38 # That's what an indirect 39 #+ reference does. 40 echo 41 echo "-------------------------------------------"; echo 42 echo 43 44 45 # Print variable 46 echo "Variable VARIABLE: $VARIABLE" 47 48 # Print a string element 49 IFS="$OLD_IFS" 50 TEST2="STRING[*]" 51 local ${!TEST2} # Indirect reference (as above). 52 echo "String element VAR2: $VAR2 from STRING" 53 54 # Print an array element 55 TEST2="ARRAY21[*]" 56 local ${!TEST2} # Indirect reference (as above). 57 echo "Array element VAR1_1: $VAR1_1 from ARRAY21" 58 } 59 60 print 61 echo 62 63 exit 0 64 65 # As the author of the script notes, 66 #+ "you can easily expand it to create named-hashes in bash." 67 # (Difficult) exercise for the reader: implement this.</PRE></TD></TR></TABLE><HR></DIV><P>--</P><P><ANAME="PRIMES0"></A></P><P>Arrays enable implementing a shell script version of the <ICLASS="FIRSTTERM">Sieve of Eratosthenes</I>. Of course, a resource-intensive application of this nature should really be written in a compiled language, such as C. It runs excruciatingly slowly as a script.</P><DIVCLASS="EXAMPLE"><HR><ANAME="EX68"></A><P><B>Example 26-13. The Sieve of Eratosthenes</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING"> 1 #!/bin/bash 2 # sieve.sh (ex68.sh) 3 4 # Sieve of Eratosthenes 5 # Ancient algorithm for finding prime numbers. 6 7 # This runs a couple of orders of magnitude slower 8 #+ than the equivalent program written in C. 9 10 LOWER_LIMIT=1 # Starting with 1. 11 UPPER_LIMIT=1000 # Up to 1000. 12 # (You may set this higher . . . if you have time on your hands.) 13 14 PRIME=1 15 NON_PRIME=0 16 17 let SPLIT=UPPER_LIMIT/2 18 # Optimization: 19 # Need to test numbers only halfway to upper limit (why?). 20 21 22 declare -a Primes 23 # Primes[] is an array. 24 25 26 initialize () 27 { 28 # Initialize the array. 29 30 i=$LOWER_LIMIT 31 until [ "$i" -gt "$UPPER_LIMIT" ] 32 do 33 Primes[i]=$PRIME 34 let "i += 1" 35 done 36 # Assume all array members guilty (prime) 37 #+ until proven innocent. 38 } 39 40 print_primes () 41 { 42 # Print out the members of the Primes[] array tagged as prime. 43 44 i=$LOWER_LIMIT 45 46 until [ "$i" -gt "$UPPER_LIMIT" ] 47 do 48 49 if [ "${Primes[i]}" -eq "$PRIME" ] 50 then 51 printf "%8d" $i 52 # 8 spaces per number gives nice, even columns. 53 fi 54 55 let "i += 1" 56 57 done 58 59 } 60 61 sift () # Sift out the non-primes. 62 { 63 64 let i=$LOWER_LIMIT+1 65 # We know 1 is prime, so let's start with 2. 66 67 until [ "$i" -gt "$UPPER_LIMIT" ] 68 do 69 70 if [ "${Primes[i]}" -eq "$PRIME" ] 71 # Don't bother sieving numbers already sieved (tagged as non-prime). 72 then 73 74 t=$i 75 76 while [ "$t" -le "$UPPER_LIMIT" ] 77 do 78 let "t += $i " 79 Primes[t]=$NON_PRIME 80 # Tag as non-prime all multiples. 81 done 82 83 fi 84 85 let "i += 1" 86 done 87 88 89 } 90 91 92 # ============================================== 93 # main () 94 # Invoke the functions sequentially. 95 initialize 96 sift 97 print_primes 98 # This is what they call structured programming. 99 # ============================================== 100 101 echo 102 103 exit 0 104 105 106 107 # -------------------------------------------------------- # 108 # Code below line will not execute, because of 'exit.' 109 110 # This improved version of the Sieve, by Stephane Chazelas, 111 #+ executes somewhat faster. 112 113 # Must invoke with command-line argument (limit of primes). 114 115 UPPER_LIMIT=$1 # From command line. 116 let SPLIT=UPPER_LIMIT/2 # Halfway to max number. 117 118 Primes=( '' $(seq $UPPER_LIMIT) ) 119 120 i=1 121 until (( ( i += 1 ) > SPLIT )) # Need check only halfway. 122 do 123 if [[ -n $Primes[i] ]] 124 then 125 t=$i 126 until (( ( t += i ) > UPPER_LIMIT )) 127 do 128 Primes[t]= 129 done 130 fi 131 done 132 echo ${Primes[*]} 133 134 exit $?</PRE></TD></TR></TABLE><HR></DIV><DIVCLASS="EXAMPLE"><HR><ANAME="EX68A"></A><P><B>Example 26-14. The Sieve of Eratosthenes, Optimized</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -