如何逐行打印 Bash 数组元素

ShellShellBeginner
立即练习

💡 本教程由 AI 辅助翻译自英文原版。如需查看原文,您可以 切换至英文原版

简介

在本教程中,你将探索 Bash 数组,并学习如何将每个元素打印在新的一行上——这是 shell 脚本编写中的常见需求。Bash 数组允许你将多个值存储在一个变量中,这使其成为在脚本中组织数据的重要工具。

在本实验结束时,你将了解如何创建数组、操作数组元素,以及使用不同的技术逐行打印数组内容。这些技能将帮助你编写更高效、易读的 shell 脚本,用于处理文件列表、处理命令输出以及自动化系统管理任务等。


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL shell(("Shell")) -.-> shell/ControlFlowGroup(["Control Flow"]) shell(("Shell")) -.-> shell/VariableHandlingGroup(["Variable Handling"]) shell/VariableHandlingGroup -.-> shell/variables_usage("Variable Usage") shell/VariableHandlingGroup -.-> shell/arrays("Arrays") shell/ControlFlowGroup -.-> shell/case("Case Statements") shell/ControlFlowGroup -.-> shell/for_loops("For Loops") subgraph Lab Skills shell/variables_usage -.-> lab-392979{{"如何逐行打印 Bash 数组元素"}} shell/arrays -.-> lab-392979{{"如何逐行打印 Bash 数组元素"}} shell/case -.-> lab-392979{{"如何逐行打印 Bash 数组元素"}} shell/for_loops -.-> lab-392979{{"如何逐行打印 Bash 数组元素"}} end

创建和理解 Bash 数组

Bash 数组允许你将多个值存储在一个变量中。下面让我们学习如何创建和使用它们。

创建你的第一个数组

在 WebIDE 中打开一个终端。默认情况下,你应该位于 /home/labex/project 目录。让我们从创建一个简单的 Bash 脚本开始:

  1. 在 WebIDE 中,通过点击资源管理器面板中的“新建文件”图标或使用“文件 > 新建文件”菜单选项,创建一个名为 array_demo.sh 的新文件。

  2. 在文件中添加以下内容:

#!/bin/bash

## 创建一个水果数组
fruits=("apple" "banana" "orange" "grape" "kiwi")

## 打印整个数组
echo "All fruits: ${fruits[@]}"

## 打印第一个元素(索引为 0)
echo "First fruit: ${fruits[0]}"

## 打印第三个元素(索引为 2)
echo "Third fruit: ${fruits[2]}"

## 打印数组中的元素数量
echo "Number of fruits: ${#fruits[@]}"
  1. 按 Ctrl+S 或使用“文件 > 保存”菜单选项保存文件。

  2. 现在,在终端中运行以下命令,使脚本可执行:

chmod +x /home/labex/project/array_demo.sh
  1. 运行脚本:
./array_demo.sh

你应该会看到类似于以下的输出:

All fruits: apple banana orange grape kiwi
First fruit: apple
Third fruit: orange
Number of fruits: 5

理解数组语法

让我们来剖析一下数组的语法:

  • 创建数组fruits=("apple" "banana" "orange" "grape" "kiwi")
    这将创建一个名为 fruits 的数组,其中包含五个元素。

  • 访问所有元素${fruits[@]}
    @ 符号表示数组的所有元素。

  • 访问特定元素${fruits[0]}${fruits[2]}
    Bash 中的数组是从 0 开始索引的,这意味着第一个元素的索引为 0。

  • 获取数组长度${#fruits[@]}
    数组引用前的 # 符号返回元素的数量。

创建数组的不同方法

让我们创建一个新脚本来演示创建数组的不同方法:

  1. 创建一个名为 array_creation.sh 的新文件:
#!/bin/bash

## 方法 1:直接声明
colors=("red" "green" "blue" "yellow")
echo "Colors array: ${colors[@]}"

## 方法 2:逐个元素赋值
shapes=()
shapes[0]="circle"
shapes[1]="square"
shapes[2]="triangle"
echo "Shapes array: ${shapes[@]}"

## 方法 3:从命令输出创建数组
files=($(ls /home/labex/project))
echo "Files in current directory: ${files[@]}"

## 方法 4:从字符串创建数组
data="one two three four"
numbers=($data)
echo "Numbers array: ${numbers[@]}"
  1. 保存文件并使其可执行:
chmod +x /home/labex/project/array_creation.sh
  1. 运行脚本:
./array_creation.sh

你应该会看到显示你创建的所有不同数组的输出。文件数组的确切输出将取决于你的目录中存在哪些文件。

这些示例展示了 Bash 数组的灵活性,以及你如何根据自己的需求以不同的方式创建它们。

操作数组元素

既然我们已经知道如何创建数组,接下来让我们学习如何通过添加、删除和修改元素来操作数组。

修改数组元素

让我们创建一个新脚本来演示数组操作:

  1. 在 WebIDE 中,创建一个名为 array_manipulation.sh 的新文件:
#!/bin/bash

## 创建一个初始数组
fruits=("apple" "banana" "orange")
echo "Initial array: ${fruits[@]}"

## 在数组末尾添加一个元素
fruits+=("grape")
echo "After adding grape: ${fruits[@]}"

## 添加多个元素
fruits+=("kiwi" "mango")
echo "After adding kiwi and mango: ${fruits[@]}"

## 更改一个元素
fruits[1]="blueberry"
echo "After changing banana to blueberry: ${fruits[@]}"

## 删除一个元素(这会留下一个空槽)
unset fruits[2]
echo "After removing the third element: ${fruits[@]}"

## 打印数组索引
echo "Array indices: ${!fruits[@]}"

## 重新创建数组以移除空槽
new_fruits=()
for fruit in "${fruits[@]}"; do
  if [[ -n "$fruit" ]]; then
    new_fruits+=("$fruit")
  fi
done

fruits=("${new_fruits[@]}")
echo "After removing empty slots: ${fruits[@]}"
  1. 保存文件并使其可执行:
chmod +x /home/labex/project/array_manipulation.sh
  1. 运行脚本:
./array_manipulation.sh

输出应显示数组在每次操作后的变化:

Initial array: apple banana orange
After adding grape: apple banana orange grape
After adding kiwi and mango: apple banana orange grape kiwi mango
After changing banana to blueberry: apple blueberry orange grape kiwi mango
After removing the third element: apple blueberry  grape kiwi mango
Array indices: 0 1 3 4 5
After removing empty slots: apple blueberry grape kiwi mango

数组切片

让我们探索如何提取数组的部分内容:

  1. 创建一个名为 array_slicing.sh 的新文件:
#!/bin/bash

## 创建一个示例数组
colors=("red" "orange" "yellow" "green" "blue" "indigo" "violet")
echo "Full array: ${colors[@]}"

## 提取子数组(起始索引和长度)
## 语法:${array[@]:start:length}
sub_array1=("${colors[@]:1:3}")
echo "Sub-array (indices 1-3): ${sub_array1[@]}"

## 从某个索引提取到末尾
sub_array2=("${colors[@]:4}")
echo "Sub-array (from index 4 to end): ${sub_array2[@]}"

## 提取最后两个元素
sub_array3=("${colors[@]: -2}") ## 注意 -2 前的空格
echo "Last two elements: ${sub_array3[@]}"
  1. 保存文件并使其可执行:
chmod +x /home/labex/project/array_slicing.sh
  1. 运行脚本:
./array_slicing.sh

输出将展示不同的数组切片方式:

Full array: red orange yellow green blue indigo violet
Sub-array (indices 1-3): orange yellow green
Sub-array (from index 4 to end): blue indigo violet
Last two elements: indigo violet

在数组中查找元素

让我们创建一个脚本来演示如何在数组中搜索元素:

  1. 创建一个名为 array_searching.sh 的新文件:
#!/bin/bash

## 创建一个示例数组
fruits=("apple" "banana" "orange" "grape" "kiwi")
echo "Our fruits: ${fruits[@]}"

## 在数组中搜索元素的函数
search_array() {
  local needle="$1"
  shift
  local haystack=("$@")

  for i in "${!haystack[@]}"; do
    if [[ "${haystack[$i]}" == "$needle" ]]; then
      echo "Found '$needle' at index $i"
      return 0
    fi
  done

  echo "'$needle' not found in the array"
  return 1
}

## 搜索一些水果
search_array "orange" "${fruits[@]}"
search_array "banana" "${fruits[@]}"
search_array "watermelon" "${fruits[@]}"
  1. 保存文件并使其可执行:
chmod +x /home/labex/project/array_searching.sh
  1. 运行脚本:
./array_searching.sh

输出将显示搜索不同元素的结果:

Our fruits: apple banana orange grape kiwi
Found 'orange' at index 2
Found 'banana' at index 1
'watermelon' not found in the array

这些示例展示了你可以对 Bash 数组执行的常见操作,这些操作是在脚本中处理数据集合的必备技能。

逐行打印数组元素

在这一步中,我们将聚焦于本次实验的主要主题:逐行打印数组元素。我们将探索在 Bash 中实现这一目标的不同方法。

方法 1:使用 for 循环

逐行打印数组元素最直接的方法是使用 for 循环:

  1. 创建一个名为 print_array_loop.sh 的新文件:
#!/bin/bash

## 创建一个示例数组
planets=("Mercury" "Venus" "Earth" "Mars" "Jupiter" "Saturn" "Uranus" "Neptune")

echo "Printing planets using a for loop:"
for planet in "${planets[@]}"; do
  echo "$planet"
done
  1. 保存文件并使其可执行:
chmod +x /home/labex/project/print_array_loop.sh
  1. 运行脚本:
./print_array_loop.sh

输出将显示每个行星位于单独的一行:

Printing planets using a for loop:
Mercury
Venus
Earth
Mars
Jupiter
Saturn
Uranus
Neptune

方法 2:使用 printf 命令

printf 命令通常比使用带有 echo 的循环更高效:

  1. 创建一个名为 print_array_printf.sh 的新文件:
#!/bin/bash

## 创建一个示例数组
planets=("Mercury" "Venus" "Earth" "Mars" "Jupiter" "Saturn" "Uranus" "Neptune")

echo "Printing planets using printf:"
printf "%s\n" "${planets[@]}"
  1. 保存文件并使其可执行:
chmod +x /home/labex/project/print_array_printf.sh
  1. 运行脚本:
./print_array_printf.sh

输出将与前一种方法相同:

Printing planets using printf:
Mercury
Venus
Earth
Mars
Jupiter
Saturn
Uranus
Neptune

方法 3:使用 IFS 变量

内部字段分隔符(Internal Field Separator,IFS)变量可用于控制数组元素的打印方式:

  1. 创建一个名为 print_array_ifs.sh 的新文件:
#!/bin/bash

## 创建一个示例数组
planets=("Mercury" "Venus" "Earth" "Mars" "Jupiter" "Saturn" "Uranus" "Neptune")

echo "Printing planets using IFS:"
## 临时将 IFS 更改为换行符
old_IFS="$IFS"
IFS=$'\n'
echo "${planets[*]}" ## 注意:在使用 IFS 时使用 * 而不是 @
IFS="$old_IFS"       ## 恢复原始的 IFS
  1. 保存文件并使其可执行:
chmod +x /home/labex/project/print_array_ifs.sh
  1. 运行脚本:
./print_array_ifs.sh

输出同样会显示每个行星位于单独的一行:

Printing planets using IFS:
Mercury
Venus
Earth
Mars
Jupiter
Saturn
Uranus
Neptune

方法 4:结合多种技术

让我们在一个更全面的示例中结合这些技术:

  1. 创建一个名为 print_array_combined.sh 的新文件:
#!/bin/bash

## 创建一个示例数组
planets=("Mercury" "Venus" "Earth" "Mars" "Jupiter" "Saturn" "Uranus" "Neptune")

echo "Using a for loop with index:"
for i in "${!planets[@]}"; do
  echo "Planet $i: ${planets[$i]}"
done

echo -e "\nUsing printf with formatting:"
printf "Planet: %s - %d letters\n" "${planets[@]}" "${#planets[@]}"

echo -e "\nSorted planets:"
printf "%s\n" "${planets[@]}" | sort
  1. 保存文件并使其可执行:
chmod +x /home/labex/project/print_array_combined.sh
  1. 运行脚本:
./print_array_combined.sh

输出将展示不同的格式化和打印数组元素的方式:

Using a for loop with index:
Planet 0: Mercury
Planet 1: Venus
Planet 2: Earth
Planet 3: Mars
Planet 4: Jupiter
Planet 5: Saturn
Planet 6: Uranus
Planet 7: Neptune

Using printf with formatting:
Planet: Mercury - 8 letters
Planet: Venus - 5 letters
Planet: Earth - 5 letters
Planet: Mars - 4 letters
Planet: Jupiter - 7 letters
Planet: Saturn - 6 letters
Planet: Uranus - 7 letters
Planet: Neptune - 7 letters

Sorted planets:
Earth
Jupiter
Mars
Mercury
Neptune
Saturn
Uranus
Venus

这些方法各有优点:

  • for 循环对初学者来说最易读。
  • printf 方法在处理大数组时更高效。
  • IFS 方法简洁,但可能不太直观。
  • 结合多种技术可以提供丰富的格式化选项。

选择最适合你具体用例和编码风格的方法。

数组的实际应用

在最后这一步,我们将探索 Bash 数组在现实世界中的应用,并运用我们所学的逐行打印元素的技术。

处理文件列表

让我们创建一个脚本来处理目录中的文件:

  1. 首先,创建一些示例文件以供使用:
mkdir -p /home/labex/project/sample_files
touch /home/labex/project/sample_files/file1.txt
touch /home/labex/project/sample_files/file2.txt
touch /home/labex/project/sample_files/file3.txt
touch /home/labex/project/sample_files/image1.jpg
touch /home/labex/project/sample_files/image2.jpg
  1. 创建一个名为 process_files.sh 的新文件:
#!/bin/bash

## 获取目录中的文件列表
file_path="/home/labex/project/sample_files"
files=($(ls "$file_path"))

echo "All files in directory:"
printf "%s\n" "${files[@]}"

echo -e "\nProcessing text files only:"
text_files=()

## 过滤文本文件
for file in "${files[@]}"; do
  if [[ "$file" == *.txt ]]; then
    text_files+=("$file")
  fi
done

## 处理每个文本文件
if [ ${#text_files[@]} -eq 0 ]; then
  echo "No text files found."
else
  echo "Found ${#text_files[@]} text files:"
  for file in "${text_files[@]}"; do
    echo "Processing $file..."
    ## 通常在这里对每个文件进行操作
    echo "  - Adding content to $file"
    echo "This is sample content" > "$file_path/$file"
  done
fi

## 验证内容
echo -e "\nContent of text files:"
for file in "${text_files[@]}"; do
  echo "--- $file ---"
  cat "$file_path/$file"
  echo "------------"
done
  1. 保存文件并使其可执行:
chmod +x /home/labex/project/process_files.sh
  1. 运行脚本:
./process_files.sh

输出将展示如何使用数组处理和过滤文件:

All files in directory:
file1.txt
file2.txt
file3.txt
image1.jpg
image2.jpg

Processing text files only:
Found 3 text files:
Processing file1.txt...
  - Adding content to file1.txt
Processing file2.txt...
  - Adding content to file2.txt
Processing file3.txt...
  - Adding content to file3.txt

Content of text files:
--- file1.txt ---
This is sample content
------------
--- file2.txt ---
This is sample content
------------
--- file3.txt ---
This is sample content
------------

创建简单的菜单系统

数组在脚本中创建菜单系统时非常有用:

  1. 创建一个名为 menu_system.sh 的新文件:
#!/bin/bash

## 定义菜单选项
options=("List Files" "Check Disk Space" "Display Date" "Display Users" "Exit")

while true; do
  echo -e "\nMenu Options:"
  ## 打印带编号的菜单
  for i in "${!options[@]}"; do
    echo "  $((i + 1)). ${options[$i]}"
  done

  ## 获取用户选择
  read -p "Enter your choice (1-${#options[@]}): " choice

  ## 转换为基于零的索引
  ((choice--))

  ## 处理选择
  case $choice in
    0) ## List Files
      echo -e "\nFiles in current directory:"
      ls -la /home/labex/project
      ;;
    1) ## Check Disk Space
      echo -e "\nDisk space usage:"
      df -h
      ;;
    2) ## Display Date
      echo -e "\nCurrent date and time:"
      date
      ;;
    3) ## Display Users
      echo -e "\nCurrently logged in users:"
      who
      ;;
    4) ## Exit
      echo "Exiting menu system. Goodbye!"
      exit 0
      ;;
    *)
      echo "Invalid choice. Please try again."
      ;;
  esac

  ## 在再次显示菜单前暂停
  read -p "Press Enter to continue..."
done
  1. 保存文件并使其可执行:
chmod +x /home/labex/project/menu_system.sh
  1. 运行脚本:
./menu_system.sh
  1. 你将看到一个菜单系统。尝试选择不同的选项以查看结果。完成后,选择选项 5 退出。

处理命令输出

数组非常适合处理命令的输出:

  1. 创建一个名为 process_command_output.sh 的新文件:
#!/bin/bash

## 获取正在运行的进程列表
echo "Getting list of processes..."
processes=($(ps -e | awk '{print $4}' | tail -n +2))

echo "Found ${#processes[@]} processes"
echo -e "\nTop 10 processes:"
printf "%s\n" "${processes[@]:0:10}"

## 统计唯一进程
echo -e "\nCounting unique process names..."
declare -A process_count

for process in "${processes[@]}"; do
  ((process_count["$process"]++))
done

echo -e "\nProcess Count Summary:"
for process in "${!process_count[@]}"; do
  echo "$process: ${process_count["$process"]}"
done | sort -rn -k2 | head -10
  1. 保存文件并使其可执行:
chmod +x /home/labex/project/process_command_output.sh
  1. 运行脚本:
./process_command_output.sh

输出将展示如何使用数组处理命令输出。确切的输出将根据你系统上运行的进程而有所不同。

这些示例展示了 Bash 数组如何在现实场景中用于解决实际问题。处理项目列表并以可读格式打印它们的能力是 shell 脚本编程的一项基本技能。

总结

在本次实验中,你学习了使用 Bash 数组的重要技能:

  1. 创建和理解数组

    • 使用不同方法声明数组
    • 访问数组元素和属性
  2. 操作数组元素

    • 添加、删除和修改元素
    • 对数组进行切片和搜索元素
  3. 逐行打印数组元素

    • 使用 for 循环遍历数组
    • 使用 printf 命令进行高效打印
    • 利用 IFS 变量进行自定义格式化
    • 结合多种技术实现高级输出格式化
  4. 实际应用

    • 处理文件列表
    • 创建菜单系统
    • 处理命令输出

这些技能为你在 Bash 脚本中使用数组奠定了坚实的基础。现在你可以高效地存储、操作和显示数据集合,使你的脚本更加健壮和通用。

请记住,掌握 Bash 数组的关键在于实践。尝试将这些技术融入你自己的脚本中,探索它们如何帮助你高效地解决现实世界中的问题。