在Bash中循环遍历一串字符串?

Mo.*_*Mo. 1371 arrays bash shell

我想编写一个循环遍历15个字符串的脚本(可能是数组?)这可能吗?

就像是:

for databaseName in listOfNames
then
  # Do something
end
Run Code Online (Sandbox Code Playgroud)

anu*_*ava 2189

你可以像这样使用它:

## declare an array variable
declare -a arr=("element1" "element2" "element3")

## now loop through the above array
for i in "${arr[@]}"
do
   echo "$i"
   # or do whatever with individual element of the array
done

# You can access them using echo "${arr[0]}", "${arr[1]}" also
Run Code Online (Sandbox Code Playgroud)

也适用于多行数组声明

declare -a arr=("element1" 
                "element2" "element3"
                "element4"
                )
Run Code Online (Sandbox Code Playgroud)

  • 在BASH中,当`$ i`可能包含空格或shell可扩展字符时,使用`""`引用变量更安全. (97认同)
  • 请注意,**“${arr[@]}”周围的双引号非常重要。**如果没有它们,for 循环将通过字符串中的任何空格分隔的子字符串而不是整个字符串来分解数组数组内的元素。即:如果你有`declare -a arr=("element 1" "element 2" "element 3")`,那么`for i in ${arr[@]}`会错误地迭代6次,因为每个字符串变成2子字符串由字符串中的空格分隔,而 `for i in "${arr[@]}"` 将根据需要正确地迭代 3 次,将每个字符串保持为单个单元,尽管其中有空格。 (61认同)
  • 不知何故,$ i周围的""需要访问每个数组元素,你能解释一下为什么或指向一些我能阅读的材料来理解它吗?非常感谢! (18认同)
  • 如果引用如上所示,它确实可以使用元素中的空格.你最好自己测试一下. (17认同)
  • `declare -a`有什么好处?我不能做一些更简单的事情,比如`arr =("element1""element2""element3")`? (13认同)
  • `declare`或`typeset`是在shell脚本中声明变量的一种显式方式. (12认同)
  • 这在#!/ bin/sh env中不起作用,你必须使用#!/ bin/bash (7认同)
  • @ChannaveerHakari:`$ {ITEMS [*]}`不适用于有空格的数组元素. (4认同)
  • 你是从哪里学到的?是否有一个手册页,其中包含有关`[@]`语法的信息? (3认同)
  • @papiro`man bash`并搜索`/ Arrays'(两个空格,第一个匹配项),使用`man less`中所示的快捷方式搜索手册页。 (3认同)
  • 谢谢,这太棒了.使用Bash shell为我工作得很好.即Ubuntu 14.04上的`#!/ bin/bash`. (2认同)
  • 即使这样对我也适用,对于$ {ITEMS [*]}中的ITEM而言;回显$ ITEM; 完成 *和@之间有什么区别。 (2认同)

4nd*_*rew 724

当然,这是可能的.

for databaseName in a b c d e f; do
  # do something like: echo $databaseName
done 
Run Code Online (Sandbox Code Playgroud)

有关详细信息,请参阅Bash循环.

  • 问题是他询问迭代数组. (18认同)
  • 如果你必须在多个地方迭代同一个数组,'declare'方法效果最好.这种方法更简洁但灵活性更低. (17认同)
  • 这种方法有什么问题?在简单的情况下,它似乎工作,然后,比@ anubhava的答案更直观. (15认同)
  • 这对于命令替换特别有效,例如`for year in $(seq 2000 2013)`. (14认同)
  • 为什么不是这个#1?它更干净,只需设置一个字符串就可以轻松地重用数组,即`DATABASES ="abcde f"`. (12认同)
  • @Nerdmaster:是的,这是一个更简单(和可移植)的代码,但是存储由变量中的空格分隔的字符串列表(实际上是单个字符串)会阻止单个字符串包含空格.[user2533809的回复](http://stackoverflow.com/a/21178462/320437)解决了这个问题.------但还有另一个问题.如果列表很长并且必须更新,则这样的更新操作需要每次都复制完整列表,因此它们将非常慢. (12认同)
  • 我对此答案的唯一问题是示例字符串都是一个字符,这可能会产生误导. (3认同)
  • @Jan-PhilipGehrcke 如果其中一个元素恰好是文件名通配符,则它将扩展为找到的文件名 (2认同)
  • 硬编码的解决方案,并没有真正提供多少价值。 (2认同)

cak*_*tux 181

这些答案都不包括反...

#!/bin/bash
## declare an array variable
declare -a array=("one" "two" "three")

# get length of an array
arraylength=${#array[@]}

# use for loop to read all values and indexes
for (( i=1; i<${arraylength}+1; i++ ));
do
  echo $i " / " ${arraylength} " : " ${array[$i-1]}
done
Run Code Online (Sandbox Code Playgroud)

输出:

1  /  3  :  one
2  /  3  :  two
3  /  3  :  three
Run Code Online (Sandbox Code Playgroud)

  • 当然,你应该从0开始理智. (88认同)
  • @bzeaman,当然 - 但是如果你对这些东西很草率,那么它需要进行上下文分析(正如你刚才所做的那样)来证明一些正确的东西,并重新分析该上下文的变化或代码是否在不同的地方重用或者用于无论出于何种其他原因,都可能出现意外的控 用稳健的方式写它,无论上下文如何都是正确的. (9认同)
  • 这应该是接受的答案,是数组元素包含空格时唯一有效的答案. (6认同)
  • 最后的回声是错误的.你并不需要引用常量,需要引用扩展,或可以安全地只是引用既如下:`回声"$ I/$ {} arraylength:$ {数组[$ I-1]}"` - 否则,如果你的`$ i`包含一个glob,它将被展开,如果它包含一个标签,它将被改为空格等. (6认同)
  • 这对于稀疏数组不起作用,即如果数组缺少元素.例如,如果你有数组元素A [1] ='xx',A [4] ='yy'和A [9] ='zz',则长度为3,循环不会处理所有元素. (4认同)
  • 这只是为了使用计数器输出示例。改变它也很简单,并且工作原理是一样的。 (2认同)
  • 不需要获取数组的长度。只需使用 `for i in "${!array[@]}";` (2认同)

Fir*_*Sky 121

for Item in Item1 Item2 Item3 Item4 ;
  do
    echo $Item
  done
Run Code Online (Sandbox Code Playgroud)

输出:

Item1
Item2
Item3
Item4
Run Code Online (Sandbox Code Playgroud)

多行

for Item in Item1 \
            Item2 \
            Item3 \
            Item4
  do
    echo $Item
  done
Run Code Online (Sandbox Code Playgroud)

输出:

Item1
Item2
Item3
Item4
Run Code Online (Sandbox Code Playgroud)


简单列表变量

List=( Item1 Item2 Item3 )
Run Code Online (Sandbox Code Playgroud)

要么

List=(
      Item1 
      Item2 
      Item3
     )
Run Code Online (Sandbox Code Playgroud)

显示列表变量:

echo ${List[*]}
Run Code Online (Sandbox Code Playgroud)

输出:

Item1 Item2 Item3
Run Code Online (Sandbox Code Playgroud)

循环列表:

for Item in ${List[*]} 
  do
    echo $Item 
  done
Run Code Online (Sandbox Code Playgroud)

输出:

Item1
Item2
Item3
Run Code Online (Sandbox Code Playgroud)

创建一个函数来浏览列表:

Loop(){
  for item in ${*} ; 
    do 
      echo ${item} 
    done
}
Loop ${List[*]}
Run Code Online (Sandbox Code Playgroud)

保留空间; 单引号或双引号列表条目和双引号列表扩展:

List=(' Item 1 '
      ' Item 2' 
      ' Item 3'
     )
for item in "${List[@]}"; 
  do 
    echo "$item"
  done 
Run Code Online (Sandbox Code Playgroud)

输出:

 Item 1
 Item 2
 Item 3
Run Code Online (Sandbox Code Playgroud)

使用declare关键字(命令)创建列表,技术上称为数组:

declare -a List=(
                 "element 1" 
                 "element 2" 
                 "element 3"
                )
for entry in "${List[@]}"
   do
     echo "$entry"
   done
Run Code Online (Sandbox Code Playgroud)

输出:

element 1
element 2
element 3
Run Code Online (Sandbox Code Playgroud)

创建关联数组.一本字典:

declare -A continent

continent[Vietnam]=Asia
continent[France]=Europe
continent[Argentina]=America

for item in "${!continent[@]}"; 
  do
    printf "$item is in ${continent[$item]} \n"
  done
Run Code Online (Sandbox Code Playgroud)

输出:

 Argentina is in America
 Vietnam is in Asia
 France is in Europe
Run Code Online (Sandbox Code Playgroud)

CVS变量或文件到列表中.
将内部字段分隔符从空格更改为您想要的任何内容.
在下面的示例中,它将更改为逗号

List="Item 1,Item 2,Item 3"
Backup_of_internal_field_separator=$IFS
IFS=,
for item in $List; 
  do
    echo $item
  done
IFS=$Backup_of_internal_field_separator
Run Code Online (Sandbox Code Playgroud)

输出:

Item 1
Item 2
Item 3
Run Code Online (Sandbox Code Playgroud)

如果需要编号:

` 
Run Code Online (Sandbox Code Playgroud)

这被称为后退.将命令放在后面.

`commend` 
Run Code Online (Sandbox Code Playgroud)

它位于键盘上的第一位和标签键上方.在标准的美国英语键盘上.

List=()
Start_count=0
Step_count=0.1
Stop_count=1
for Item in `seq $Start_count $Step_count $Stop_count`
    do 
       List+=(Item_$Item)
    done
for Item in ${List[*]}
    do 
        echo $Item
    done
Run Code Online (Sandbox Code Playgroud)

输出是:

Item_0.0
Item_0.1
Item_0.2
Item_0.3
Item_0.4
Item_0.5
Item_0.6
Item_0.7
Item_0.8
Item_0.9
Item_1.0
Run Code Online (Sandbox Code Playgroud)

更熟悉bashes行为:

在文件中创建列表

cat <<EOF> List_entries.txt
Item1
Item 2 
'Item 3'
"Item 4"
Item 7 : *
"Item 6 : * "
"Item 6 : *"
Item 8 : $PWD
'Item 8 : $PWD'
"Item 9 : $PWD"
EOF
Run Code Online (Sandbox Code Playgroud)

将列表文件读入列表并显示

List=$(cat List_entries.txt)
echo $List
echo '$List'
echo "$List"
echo ${List[*]}
echo '${List[*]}'
echo "${List[*]}"
echo ${List[@]}
echo '${List[@]}'
echo "${List[@]}"
Run Code Online (Sandbox Code Playgroud)

BASH命令行参考手册:shell中某些字符或单词的特殊含义.

  • **这是错的.**需要``$ {List [@]}"`是正确的,**带引号**.`$ {List [@]}`错了.`$ {List [*]}`错了.尝试`List =("**first item*""*second item*")` - 对于'$ {List [@]}"中的项目,你会得到正确的行为.回声"$ item"; 完成,但不是来自任何其他变体. (3认同)
  • 我仍然强烈建议展示更正确/更稳健的方法*first*。人们通常会选择第一个看起来可行的答案;如果那个答案有隐藏的警告,他们可能只会在以后暴露自己。(不仅仅是通配符因为缺少引用而被破坏;`List=( "first item" "second item" )` 也会被分解为`first`、`item`、`second`、`item`)。 (2认同)
  • 你在反驳我从未提出过的主张。我对 bash 的引用语义非常熟悉——请参阅 https://stackoverflow.com/tags/bash/topusers (2认同)

use*_*809 106

本着与4ndrew的回答一样的精神:

listOfNames="RA
RB
R C
RD"

# To allow for other whitespace in the string:
# 1. add double quotes around the list variable, or
# 2. see the IFS note (under 'Side Notes')

for databaseName in "$listOfNames"   #  <-- Note: Added "" quotes.
do
  echo "$databaseName"  # (i.e. do action / processing of $databaseName here...)
done

# Outputs
# RA
# RB
# R C
# RD
Run Code Online (Sandbox Code Playgroud)

B.名字中没有空格:

listOfNames="RA
RB
R C
RD"

for databaseName in $listOfNames  # Note: No quotes
do
  echo "$databaseName"  # (i.e. do action / processing of $databaseName here...)
done

# Outputs
# RA
# RB
# R
# C
# RD
Run Code Online (Sandbox Code Playgroud)

笔记

  1. 在第二个示例中,using使用listOfNames="RA RB R C RD"相同的输出.

其他引入数据的方法包括:

从stdin读取

# line delimited (each databaseName is stored on a line)
while read databaseName
do
  echo "$databaseName"  # i.e. do action / processing of $databaseName here...
done # <<< or_another_input_method_here
Run Code Online (Sandbox Code Playgroud)
  1. 可以在脚本中指定bash IFS "字段分隔符到行"[ 1 ]分隔符以允许其他空格(即IFS='\n',对于MacOS IFS='\r')
  2. 我也喜欢接受的答案:) - 我已经将这些片段作为其他有用的方式包含在内,也可以回答这个问题.
  3. 包括#!/bin/bash在脚本文件的顶部表示执行环境.
  4. 我花了几个月的时间才弄清楚如何编写这个简单:)

其他来源(读取循环时)

  • 这对我不起作用.`$ databaseName`只包含整个列表,因此只进行一次迭代. (7认同)

Fiz*_*han 41

你可以使用的语法 ${arrayName[@]}

#!/bin/bash
# declare an array called files, that contains 3 values
files=( "/etc/passwd" "/etc/group" "/etc/hosts" )
for i in "${files[@]}"
do
    echo "$i"
done
Run Code Online (Sandbox Code Playgroud)


Kof*_*ofi 36

我在 GitHub 更新中使用了这种方法,我发现它很简单。

## declare an array variable
arr_variable=("kofi" "kwame" "Ama")

## now loop through the above array
for i in "${arr_variable[@]}"
do
   echo "$i"


done
   
Run Code Online (Sandbox Code Playgroud)

您可以使用具有三个表达式(C 风格)的计数器来迭代 bash 数组值,以读取循环语法的所有值和索引:

declare -a kofi=("kofi" "kwame" "Ama")
 
# get the length of the array
length=${#kofi[@]}

for (( j=0; j<${length}; j++ ));
do
  print (f "Current index %d with value %s\n" $j "${kofi[$j]}")
done
Run Code Online (Sandbox Code Playgroud)


小智 20

这也很容易阅读:

FilePath=(
    "/tmp/path1/"    #FilePath[0]
    "/tmp/path2/"    #FilePath[1]
)

#Loop
for Path in "${FilePath[@]}"
do
    echo "$Path"
done
Run Code Online (Sandbox Code Playgroud)

  • 只有当我正确地设置IFS变量_before_ FilePath数组定义时,这个对我来说很清楚(包括在FilePath数组元素中使用空格和变量替换):`IFS = $'\n'`这可能适用于其他解决方案在这种情况下也是如此 (3认同)

Doo*_*nob 20

很惊讶没有人发布这个 - 如果你在循环数组时需要元素的索引,你可以这样做:

arr=(foo bar baz)

for i in ${!arr[@]}
do
    echo $i "${arr[i]}"
done
Run Code Online (Sandbox Code Playgroud)

输出:

0 foo
1 bar
2 baz
Run Code Online (Sandbox Code Playgroud)

我觉得这比"传统的"循环风格(for (( i=0; i<${#arr[@]}; i++ )))要优雅得多.

(${!arr[@]}并且$i不需要引用,因为它们只是数字;有些人会建议引用它们,但这只是个人偏好.)

  • 这确实应该是选择的答案。1:简单易读。2:它正确处理空白,没有 IFS 废话妨碍。3:它可以正确处理稀疏数组。 (3认同)

F. *_*uri 8

脚本或函数的隐式数组:

除了anubhava的正确答案:如果循环的基本语法是:

for var in "${arr[@]}" ;do ...$var... ;done
Run Code Online (Sandbox Code Playgroud)

有一个特殊的情况下:

当运行一个脚本或函数,参数在命令行通过将被分配给$@数组变量,你可以访问$1,$2,$3,等等.

这可以填充(用于测试)

set -- arg1 arg2 arg3 ...
Run Code Online (Sandbox Code Playgroud)

一个循环这个阵列可以简单地写成:

for item ;do
    echo "This is item: $item."
  done
Run Code Online (Sandbox Code Playgroud)

请注意,保留的工作in不存在,也没有数组名称!

样品:

set -- arg1 arg2 arg3 ...
for item ;do
    echo "This is item: $item."
  done
This is item: arg1.
This is item: arg2.
This is item: arg3.
This is item: ....
Run Code Online (Sandbox Code Playgroud)

请注意,这与

for item in "$@";do
    echo "This is item: $item."
  done
Run Code Online (Sandbox Code Playgroud)

然后进入一个脚本:

#!/bin/bash

for item ;do
    printf "Doing something with '%s'.\n" "$item"
  done
Run Code Online (Sandbox Code Playgroud)

在脚本保存此myscript.sh,chmod +x myscript.sh

./myscript.sh arg1 arg2 arg3 ...
Doing something with 'arg1'.
Doing something with 'arg2'.
Doing something with 'arg3'.
Doing something with '...'.
Run Code Online (Sandbox Code Playgroud)

功能相同:

myfunc() { for item;do cat <<<"Working about '$item'."; done ; }
Run Code Online (Sandbox Code Playgroud)

然后

myfunc item1 tiem2 time3
Working about 'item1'.
Working about 'tiem2'.
Working about 'time3'.
Run Code Online (Sandbox Code Playgroud)


nro*_*ose 7

listOfNames="db_one db_two db_three"
for databaseName in $listOfNames
do
  echo $databaseName
done
Run Code Online (Sandbox Code Playgroud)

要不就

for databaseName in db_one db_two db_three
do
  echo $databaseName
done
Run Code Online (Sandbox Code Playgroud)


Jam*_*mie 6

这与 user2533809 的答案类似,但每个文件将作为单独的命令执行。

#!/bin/bash
names="RA
RB
R C
RD"

while read -r line; do
    echo line: "$line"
done <<< "$names"
Run Code Online (Sandbox Code Playgroud)


ras*_*dcs 6

简单方法:

arr=("sharlock"  "bomkesh"  "feluda" )  ##declare array

len=${#arr[*]}  # it returns the array length

#iterate with while loop
i=0
while [ $i -lt $len ]
do
    echo ${arr[$i]}
    i=$((i+1))
done


#iterate with for loop
for i in $arr
do
  echo $i
done

#iterate with splice
 echo ${arr[@]:0:3}
Run Code Online (Sandbox Code Playgroud)


小智 5

该声明数组不适用于Korn shell。将以下示例用于Korn shell:

promote_sla_chk_lst="cdi xlob"

set -A promote_arry $promote_sla_chk_lst

for i in ${promote_arry[*]};
    do
            echo $i
    done
Run Code Online (Sandbox Code Playgroud)

  • 很高兴知道,但是这个问题是关于bash的。 (5认同)
  • 尝试在编辑器中使用代码突出显示功能,使您的代码看起来不错。 (2认同)

Sim*_*mar 5

尝试这个。它正在工作并经过测试。

for k in "${array[@]}"
do
    echo $k
done

# For accessing with the echo command: echo ${array[0]}, ${array[1]}
Run Code Online (Sandbox Code Playgroud)

  • ...在 shell 中调用一些“测试”的东西之前,一定要检查极端情况,其中空格和 glob 都在其中。 (6认同)
  • 这实际上不能正常工作。试试 `array=( "hello world" )` 或 `arrray=( "*" )`;在第一种情况下它会分别打印 `hello` 和 `world`,在第二种情况下它会打印一个文件列表而不是 `*` (3认同)