ChinaUnix首页 > 精华文章 > Shell > 正文

[精彩] 为感谢ChinaUnix上兄弟的无私帮助


http://www.chinaunix.net 作者:gzgzgz  发表于:2005-04-15 09:32:28
发表评论】 【查看原文】 【Shell讨论区】【关闭

为感谢ChinaUnix上兄弟的无私帮助,我贡献一段关于shell数组的翻译,不足之处望大家海涵,海纳百川,有容乃大,希望大家尽己所能,发挥自由之精神。 (不知道刚才咋回事,发到Linux版了)

bash提供一维数组。使用一个数组前可以显式地以declare声明(言下之意,也可以不)。在数组元素的最大数目上并无约束,甚至,不要求数组元素被连续赋值。其下标从0开始。 

一个数组可以通过如下赋值方式而自动创建: 
name[subscript]=value 
下标subscript必须为数,大于或等于0,显式声明如下: 
declare -a name 
为自己方便,也可写成 
declare -a name[subscript],shell解释时忽略subscript. 

用如下方式可对整个数组赋值 
name=(value1 ... valuen) 

其中value可用[subscript]=代替,从而具体指定对那个元素赋值。例子如下: 

[shark@phi ver1.2]$ name=([0]=1 [2]=34 [3]=45) 
[shark@phi ver1.2]$ echo ${name[0]} 

[shark@phi ver1.2]$ echo ${name[1]} 

[shark@phi ver1.2]$ echo ${name[2]} 
34 
[shark@phi ver1.2]$ echo ${name[3]} 
45 
[shark@phi ver1.2]$ echo ${name[4]} 

[shark@phi ver1.2]$ 
(不过这样太不方便,个人意见,还不如按下标一个个写) 
引用数组变量用 
${name[subscript]} 
必须用{},否则shell将有误解,而不予接受。 

若下标为`@' or `*', 则做通配符解,代指所有数组元素。 
[shark@phi ver1.2]$ echo ${name[*]} 
1 34 45 
[shark@phi ver1.2]$ 
[shark@phi ver1.2]$ echo ${name[@]} 
1 34 45 

但不可做赋值 
name[*]=1    是错的。 

数组元素可以是字符串。元素间以环境变量IFS的第一个字符分隔。 

[shark@phi ver1.2]$ name=(hello glad to meet you) 
[shark@phi ver1.2]$ echo ${name[0]} 
hello 
[shark@phi ver1.2]$ echo ${name[1]} 
glad 
[shark@phi ver1.2]$ echo ${name[2]} 
to 
[shark@phi ver1.2]$ echo ${name[3]} 
meet 
[shark@phi ver1.2]$ echo ${name[4]} 
you 

若要跨过分隔约束,用双引号括起 
[shark@phi ver1.2]$ name=("hello glad" to meet you) 
[shark@phi ver1.2]$ echo ${name[0]} 
hello glad 
[shark@phi ver1.2]$ echo ${name[1]} 
to 
[shark@phi ver1.2]$ echo ${name[2]} 
meet 
[shark@phi ver1.2]$ echo ${name[3]} 
you 

数组元素个数以${#name[subscript]} 计得 
无下标的数组变量引用等价于引用其第零个元素。 
用unset命令可以销毁一个数组 
unset name    或者   unset name[*] 
也可以只销毁一个元素 
unset name[subscript] 

read命令支持以 -a 参数从标准输入读入数组。



 gzgzgz 回复于:2005-04-14 23:52:38

再灌一篇以供大家参考
#!/bin/bash
# array-ops.sh: More fun with arrays.


array=( zero one two three four five )
# Element 0   1   2    3     4    5

echo ${array[0]}       #  zero
echo ${array:0}        #  zero
                       #  Parameter expansion of first element,
                       #+ starting at position # 0 (1st character).
echo ${array:1}        #  ero
                       #  Parameter expansion of first element,
                       #+ starting at position # 1 (2nd character).

echo "--------------"

echo ${#array[0]}      #  4
                       #  Length of first element of array.
echo ${#array}         #  4
                       #  Length of first element of array.
                       #  (Alternate notation)

echo ${#array[1]}      #  3
                       #  Length of second element of array.
                       #  Arrays in Bash have zero-based indexing.

echo ${#array[*]}      #  6
                       #  Number of elements in array.
echo ${#array[@]}      #  6
                       #  Number of elements in array.

echo "--------------"

array2=( [0]="first element" [1]="second element" [3]="fourth element" )

echo ${array2[0]}      # first element
echo ${array2[1]}      # second element
echo ${array2[2]}      #
                       # Skipped in initialization, and therefore null.
echo ${array2[3]}      # fourth element


exit 0


 gzgzgz 回复于:2005-04-14 23:59:07

不怕死,再灌#!/bin/bash
# array-strops.sh: String operations on arrays.
# Script by Michael Zick.
# Used with permission.

#  In general, any string operation in the ${name ... } notation
#+ can be applied to all string elements in an array
#+ with the ${name[@] ... } or ${name[*] ...} notation.


arrayZ=( one two three four five five )

echo

# Trailing Substring Extraction
echo ${arrayZ[@]:0}     # one two three four five five
                        # All elements.

echo ${arrayZ[@]:1}     # two three four five five
                        # All elements following element[0].

echo ${arrayZ[@]:1:2}   # two three
                        # Only the two elements after element[0].

echo "-----------------------"

#  Substring Removal
#  Removes shortest match from front of string(s),
#+ where the substring is a regular expression.

echo ${arrayZ[@]#f*r}   # one two three five five
                        # Applied to all elements of the array.
                        # Matches "four" and removes it.

# Longest match from front of string(s)
echo ${arrayZ[@]##t*e}  # one two four five five
                        # Applied to all elements of the array.
                        # Matches "three" and removes it.

# Shortest match from back of string(s)
echo ${arrayZ[@]%h*e}   # one two t four five five
                        # Applied to all elements of the array.
                        # Matches "hree" and removes it.

# Longest match from back of string(s)
echo ${arrayZ[@]%%t*e}  # one two four five five
                        # Applied to all elements of the array.
                        # Matches "three" and removes it.

echo "-----------------------"

# Substring Replacement

# Replace first occurance of substring with replacement
echo ${arrayZ[@]/fiv/XYZ}   # one two three four XYZe XYZe
                            # Applied to all elements of the array.

# Replace all occurances of substring
echo ${arrayZ[@]//iv/YY}    # one two three four fYYe fYYe
                            # Applied to all elements of the array.

# Delete all occurances of substring
# Not specifing a replacement means 'delete'
echo ${arrayZ[@]//fi/}      # one two three four ve ve
                            # Applied to all elements of the array.

# Replace front-end occurances of substring
echo ${arrayZ[@]/#fi/XY}    # one two three four XYve XYve
                            # Applied to all elements of the array.

# Replace back-end occurances of substring
echo ${arrayZ[@]/%ve/ZZ}    # one two three four fiZZ fiZZ
                            # Applied to all elements of the array.

echo ${arrayZ[@]/%o/XX}     # one twXX three four five five
                            # Why?

echo "-----------------------"


# Before reaching for awk (or anything else) --
# Recall:
#   $( ... ) is command substitution.
#   Functions run as a sub-process.
#   Functions write their output to stdout.
#   Assignment reads the function's stdout.
#   The name[@] notation specifies a "for-each" operation.

newstr() {
    echo -n "!!!"
}

echo ${arrayZ[@]/%e/$(newstr)}
# on!!! two thre!!! four fiv!!! fiv!!!
# Q.E.D: The replacement action is an 'assignment.'

#  Accessing the "For-Each"
echo ${arrayZ[@]//*/$(newstr optional_arguments)}
#  Now, if Bash would just pass the matched string as $0
#+ to the function being called . . .

echo

exit 0


 一梦如是 回复于:2005-04-15 00:07:59

啥时候结束,提醒一声,偶好收藏~~


 寂寞烈火 回复于:2005-04-15 00:08:54

引用:原帖由 "gzgzgz" 发表:
newstr optional_arguments)}
#  Now, if Bash would just pass the matched string as $0
#+ to the function being called . . .

echo

exit 0


 :mrgreen:  :mrgreen:  OK! learning ...


 gzgzgz 回复于:2005-04-15 09:32:28

:mrgreen: 数组的向后扩展# Try extending those arrays.

# Adding an element to an array.
array0=( "${array0[@]}" "new1" )
array1=( "${array1[@]}" "new1" )
array2=( "${array2[@]}" "new1" )

ListArray

# or
array0[${#array0[*]}]="new2"
array1[${#array1[*]}]="new2"
array2[${#array2[*]}]="new2

数组的拷贝与合并

#! /bin/bash
# CopyArray.sh
#
# This script written by Michael Zick.
# Used here with permission.

#  How-To "Pass by Name & Return by Name"
#+ or "Building your own assignment statement".


CpArray_Mac() {

# Assignment Command Statement Builder

    echo -n 'eval '
    echo -n "$2"                    # Destination name
    echo -n '=( ${'
    echo -n "$1"                    # Source name
    echo -n '[@]} )'

# That could all be a single command.
# Matter of style only.
}

declare -f CopyArray                # Function "Pointer"
CopyArray=CpArray_Mac               # Statement Builder

Hype()
{

# Hype the array named $1.
# (Splice it together with array containing "Really Rocks".)
# Return in array named $2.

    local -a TMP
    local -a hype=( Really Rocks )

    $($CopyArray $1 TMP)
    TMP=( ${TMP[@]} ${hype[@]} )
    $($CopyArray TMP $2)
}

declare -a before=( Advanced Bash Scripting )
declare -a after

echo "Array Before = ${before[@]}"

Hype before after

echo "Array After = ${after[@]}"

# Too much hype?

echo "What ${after[@]:3:2}?"

declare -a modest=( ${after[@]:2:1} ${after[@]:3:2} )
#                    ---- substring extraction ----

echo "Array Modest = ${modest[@]}"

# What happened to 'before' ?

echo "Array Before = ${before[@]}"

exit 0

数组合并再一篇实例
#! /bin/bash
# array-append.bash

# Copyright (c) Michael S. Zick, 2003, All rights reserved.
# License: Unrestricted reuse in any form, for any purpose.
# Version: $ID$
#
# Slightly modified in formatting by M.C.


# Array operations are Bash-specific.
# Legacy UNIX /bin/sh lacks equivalents.


#  Pipe the output of this script to 'more'
#+ so it doesn't scroll off the terminal.


# Subscript packed.
declare -a array1=( zero1 one1 two1 )
# Subscript sparse ([1] is not defined).
declare -a array2=( [0]=zero2 [2]=two2 [3]=three2 )

echo
echo '- Confirm that the array is really subscript sparse. -'
echo "Number of elements: 4"        # Hard-coded for illustration.
for (( i = 0 ; i < 4 ; i++ ))
do
    echo "Element [$i]: ${array2[$i]}"
done
# See also the more general code example in basics-reviewed.bash.


declare -a dest

# Combine (append) two arrays into a third array.
echo
echo 'Conditions: Unquoted, default IFS, All-Elements-Of operator'
echo '- Undefined elements not present, subscripts not maintained. -'
# # The undefined elements do not exist; they are not being dropped.

dest=( ${array1[@]} ${array2[@]} )
# dest=${array1[@]}${array2[@]}     # Strange results, possibly a bug.

# Now, list the result.
echo
echo '- - Testing Array Append - -'
cnt=${#dest[@]}

echo "Number of elements: $cnt"
for (( i = 0 ; i < cnt ; i++ ))
do
    echo "Element [$i]: ${dest[$i]}"
done

# Assign an array to a single array element (twice).
dest[0]=${array1[@]}
dest[1]=${array2[@]}

# List the result.
echo
echo '- - Testing modified array - -'
cnt=${#dest[@]}

echo "Number of elements: $cnt"
for (( i = 0 ; i < cnt ; i++ ))
do
    echo "Element [$i]: ${dest[$i]}"
done

# Examine the modified second element.
echo
echo '- - Reassign and list second element - -'

declare -a subArray=${dest[1]}
cnt=${#subArray[@]}

echo "Number of elements: $cnt"
for (( i = 0 ; i < cnt ; i++ ))
do
    echo "Element [$i]: ${subArray[$i]}"
done

#  The assignment of an entire array to a single element
#+ of another array using the '=${ ... }' array assignment
#+ has converted the array being assigned into a string,
#+ with the elements separated by a space (the first character of IFS).

# If the original elements didn't contain whitespace . . .
# If the original array isn't subscript sparse . . .
# Then we could get the original array structure back again.

# Restore from the modified second element.
echo
echo '- - Listing restored element - -'

declare -a subArray=( ${dest[1]} )
cnt=${#subArray[@]}

echo "Number of elements: $cnt"
for (( i = 0 ; i < cnt ; i++ ))
do
    echo "Element [$i]: ${subArray[$i]}"
done
echo '- - Do not depend on this behavior. - -'
echo '- - This behavior is subject to change - -'
echo '- - in versions of Bash newer than version 2.05b - -'

# MSZ: Sorry about any earlier confusion folks.

exit 0


 :em11: 冒泡排序

#!/bin/bash
# bubble.sh: Bubble sort, of sorts.

# Recall the algorithm for a bubble sort. In this particular version...

#  With each successive pass through the array to be sorted,
#+ compare two adjacent elements, and swap them if out of order.
#  At the end of the first pass, the "heaviest" element has sunk to bottom.
#  At the end of the second pass, the next "heaviest" one has sunk next to bottom.
#  And so forth.
#  This means that each successive pass needs to traverse less of the array.
#  You will therefore notice a speeding up in the printing of the later passes.


exchange()
{
  # Swaps two members of the array.
  local temp=${Countries[$1]} #  Temporary storage
                              #+ for element getting swapped out.
  Countries[$1]=${Countries[$2]}
  Countries[$2]=$temp
  
  return
}  

declare -a Countries  #  Declare array,
                      #+ optional here since it's initialized below.

#  Is it permissable to split an array variable over multiple lines
#+ using an escape (\)?
#  Yes.

Countries=(Netherlands Ukraine Zaire Turkey Russia Yemen Syria \
Brazil Argentina Nicaragua Japan Mexico Venezuela Greece England \
Israel Peru Canada Oman Denmark Wales France Kenya \
Xanadu Qatar Liechtenstein Hungary)

# "Xanadu" is the mythical place where, according to Coleridge,
#+ Kubla Khan did a pleasure dome decree.


clear                      # Clear the screen to start with. 

echo "0: ${Countries[*]}"  # List entire array at pass 0.

number_of_elements=${#Countries[@]}
let "comparisons = $number_of_elements - 1"

count=1 # Pass number.

while [ "$comparisons" -gt 0 ]          # Beginning of outer loop
do

  index=0  # Reset index to start of array after each pass.

  while [ "$index" -lt "$comparisons" ] # Beginning of inner loop
  do
    if [ ${Countries[$index]} \> ${Countries[`expr $index + 1`]} ]
    #  If out of order...
    #  Recalling that \> is ASCII comparison operator
    #+ within single brackets.

    #  if [[ ${Countries[$index]} > ${Countries[`expr $index + 1`]} ]]
    #+ also works.
    then
      exchange $index `expr $index + 1`  # Swap.
    fi  
    let "index += 1"
  done # End of inner loop

# ----------------------------------------------------------------------
# Paulo Marcel Coelho Aragao suggests for-loops as a simpler altenative.
#
# for (( last = $number_of_elements - 1 ; last > 1 ; last-- ))
# do
#     for (( i = 0 ; i < last ; i++ ))
#     do
#         [[ "${Countries[$i]}" > "${Countries[$((i+1))]}" ]] \
#             && exchange $i $((i+1))
#     done
# done
# ----------------------------------------------------------------------
  

let "comparisons -= 1" #  Since "heaviest" element bubbles to bottom,
                       #+ we need do one less comparison each pass.

echo
echo "$count: ${Countries[@]}"  # Print resultant array at end of each pass.
echo
let "count += 1"                # Increment pass count.

done                            # End of outer loop
                                # All done.

exit 0
灌了这么多怕是要被斑竹打出去了 :em06:




原文链接:http://bbs.chinaunix.net/viewthread.php?tid=530586
转载请注明作者名及原文出处