简介
在本教程中,你将探索 Bash 数组,并学习如何将每个元素打印在新的一行上——这是 shell 脚本编写中的常见需求。Bash 数组允许你将多个值存储在一个变量中,这使其成为在脚本中组织数据的重要工具。
在本实验结束时,你将了解如何创建数组、操作数组元素,以及使用不同的技术逐行打印数组内容。这些技能将帮助你编写更高效、易读的 shell 脚本,用于处理文件列表、处理命令输出以及自动化系统管理任务等。
在本教程中,你将探索 Bash 数组,并学习如何将每个元素打印在新的一行上——这是 shell 脚本编写中的常见需求。Bash 数组允许你将多个值存储在一个变量中,这使其成为在脚本中组织数据的重要工具。
在本实验结束时,你将了解如何创建数组、操作数组元素,以及使用不同的技术逐行打印数组内容。这些技能将帮助你编写更高效、易读的 shell 脚本,用于处理文件列表、处理命令输出以及自动化系统管理任务等。
Bash 数组允许你将多个值存储在一个变量中。下面让我们学习如何创建和使用它们。
在 WebIDE 中打开一个终端。默认情况下,你应该位于 /home/labex/project
目录。让我们从创建一个简单的 Bash 脚本开始:
在 WebIDE 中,通过点击资源管理器面板中的“新建文件”图标或使用“文件 > 新建文件”菜单选项,创建一个名为 array_demo.sh
的新文件。
在文件中添加以下内容:
#!/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[@]}"
按 Ctrl+S 或使用“文件 > 保存”菜单选项保存文件。
现在,在终端中运行以下命令,使脚本可执行:
chmod +x /home/labex/project/array_demo.sh
./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[@]}
数组引用前的 #
符号返回元素的数量。
让我们创建一个新脚本来演示创建数组的不同方法:
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[@]}"
chmod +x /home/labex/project/array_creation.sh
./array_creation.sh
你应该会看到显示你创建的所有不同数组的输出。文件数组的确切输出将取决于你的目录中存在哪些文件。
这些示例展示了 Bash 数组的灵活性,以及你如何根据自己的需求以不同的方式创建它们。
既然我们已经知道如何创建数组,接下来让我们学习如何通过添加、删除和修改元素来操作数组。
让我们创建一个新脚本来演示数组操作:
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[@]}"
chmod +x /home/labex/project/array_manipulation.sh
./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
让我们探索如何提取数组的部分内容:
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[@]}"
chmod +x /home/labex/project/array_slicing.sh
./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
让我们创建一个脚本来演示如何在数组中搜索元素:
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[@]}"
chmod +x /home/labex/project/array_searching.sh
./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 中实现这一目标的不同方法。
逐行打印数组元素最直接的方法是使用 for 循环:
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
chmod +x /home/labex/project/print_array_loop.sh
./print_array_loop.sh
输出将显示每个行星位于单独的一行:
Printing planets using a for loop:
Mercury
Venus
Earth
Mars
Jupiter
Saturn
Uranus
Neptune
printf
命令通常比使用带有 echo
的循环更高效:
print_array_printf.sh
的新文件:#!/bin/bash
## 创建一个示例数组
planets=("Mercury" "Venus" "Earth" "Mars" "Jupiter" "Saturn" "Uranus" "Neptune")
echo "Printing planets using printf:"
printf "%s\n" "${planets[@]}"
chmod +x /home/labex/project/print_array_printf.sh
./print_array_printf.sh
输出将与前一种方法相同:
Printing planets using printf:
Mercury
Venus
Earth
Mars
Jupiter
Saturn
Uranus
Neptune
内部字段分隔符(Internal Field Separator,IFS)变量可用于控制数组元素的打印方式:
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
chmod +x /home/labex/project/print_array_ifs.sh
./print_array_ifs.sh
输出同样会显示每个行星位于单独的一行:
Printing planets using IFS:
Mercury
Venus
Earth
Mars
Jupiter
Saturn
Uranus
Neptune
让我们在一个更全面的示例中结合这些技术:
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
chmod +x /home/labex/project/print_array_combined.sh
./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
这些方法各有优点:
printf
方法在处理大数组时更高效。选择最适合你具体用例和编码风格的方法。
在最后这一步,我们将探索 Bash 数组在现实世界中的应用,并运用我们所学的逐行打印元素的技术。
让我们创建一个脚本来处理目录中的文件:
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
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
chmod +x /home/labex/project/process_files.sh
./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
------------
数组在脚本中创建菜单系统时非常有用:
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
chmod +x /home/labex/project/menu_system.sh
./menu_system.sh
数组非常适合处理命令的输出:
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
chmod +x /home/labex/project/process_command_output.sh
./process_command_output.sh
输出将展示如何使用数组处理命令输出。确切的输出将根据你系统上运行的进程而有所不同。
这些示例展示了 Bash 数组如何在现实场景中用于解决实际问题。处理项目列表并以可读格式打印它们的能力是 shell 脚本编程的一项基本技能。
在本次实验中,你学习了使用 Bash 数组的重要技能:
创建和理解数组
操作数组元素
逐行打印数组元素
printf
命令进行高效打印实际应用
这些技能为你在 Bash 脚本中使用数组奠定了坚实的基础。现在你可以高效地存储、操作和显示数据集合,使你的脚本更加健壮和通用。
请记住,掌握 Bash 数组的关键在于实践。尝试将这些技术融入你自己的脚本中,探索它们如何帮助你高效地解决现实世界中的问题。