Shell脚本基础应用
1.脚本运行方法
创建目录
[root@localhost opt]# mkdir learn
执行文件的方法[root@localhost opt]# cd learn/
[root@localhost learn]# ls
[root@localhost learn]# vi hello.sh
[root@localhost learn]# .hello.sh
[root@localhost learn]# vi hello.sh
[root@localhost learn]# .hello.sh
[root@localhost learn]# vi hello.sh
[root@localhost learn]# .hello.sh
[root@localhost learn]# vi hello.sh
[root@localhost learn]# source hello.sh
helloworld!
[root@localhost learn]# . hello.sh
helloworld!
[root@localhost learn]# bash hello.sh
helloworld!
[root@localhost learn]# ll
total 4
-rw-r--r--. 1 root root 59 Oct 6 07:12 hello.sh
[root@localhost learn]# chmod u+x hello.sh
[root@localhost learn]# ll
total 4
-rwxr--r--. 1 root root 59 Oct 6 07:12 hello.sh
[root@localhost learn]# ./hello.sh
helloworld!
[root@localhost learn]#
2.脚本传入参数
#!/usr/bin/bash
#这是注释,用#号
echo "helloworld!"
echo "一共有 $# 个参数"
#在Shell中,最多只能有9个参数
echo "第一个参数是 $1"
echo "第二个参数是 $2"
echo "第十个参数是 $10"
如果参数超过10个该怎么处理?
在 Shell 脚本中,当参数超过 9 个时,不能直接使用 $10、$11 这样的形式,因为 Shell 会将 $10 解释为 $1 后面跟一个 0。
#使用数组:
#!/bin/bash# 将所有参数保存到数组
args=("$@")# 通过数组下标访问参数
echo "第10个参数: ${args[9]}"
echo "第11个参数: ${args[10]}"
echo "第12个参数: ${args[11]}"# 遍历所有参数
for i in "${!args[@]}"; doecho "参数 $((i+1)): ${args[i]}"
done
#!/bin/bash# 在 bash 4.0+ 和现代 shell 中支持 ${10} 形式
echo "第10个参数: ${10}"
echo "第11个参数: ${11}"
echo "第12个参数: ${12}"
#!/usr/bin/bash
#通过参数来确定对某个文件进行查找,并输出相应的行号和行数,只接收1个参数
filename=$1
grep -n root $filename
请完善以下脚本,明确提醒用户,如果输入参数错误,则给予及时提醒。
#!/usr/bin/bashwhile true; do# 清屏(可选)# clearecho "=== 文件内容查找工具 ==="echo "请输入要查找的文件路径(输入 'q' 退出):"read -p "文件: " filename# 检查是否退出if [ "$filename" = "q" ] || [ "$filename" = "quit" ]; thenecho "再见!"exit 0fi# 检查文件是否存在if [ ! -e "$filename" ]; thenecho "错误:文件 '$filename' 不存在!"echo "请检查文件路径后重试。"echo ""read -p "按回车键继续..."continuefi# 检查是否是普通文件if [ ! -f "$filename" ]; thenecho "错误:'$filename' 不是一个普通文件!"echo ""read -p "按回车键继续..."continuefi# 检查文件是否可读if [ ! -r "$filename" ]; thenecho "错误:没有读取文件 '$filename' 的权限!"echo ""read -p "按回车键继续..."continuefi# 检查文件是否为空if [ ! -s "$filename" ]; thenecho "警告:文件 '$filename' 为空!"echo ""read -p "按回车键继续..."continuefi# 执行查找操作echo ""echo "在文件 '$filename' 中查找包含 'root' 的行:"echo "=============================================="grep -n "root" "$filename"# 检查grep执行结果grep_result=$?if [ $grep_result -eq 0 ]; thenecho "=============================================="echo "查找完成。"elif [ $grep_result -eq 1 ]; thenecho "--------------------------------------------------"echo "未找到包含 'root' 的行。"echo "=============================================="elseecho "=============================================="echo "查找过程中出现错误。"fiecho ""echo "是否继续查找其他文件?"read -p "输入 'q' 退出,或按回车键继续: " choiceif [ "$choice" = "q" ] || [ "$choice" = "quit" ]; thenecho "再见!"exit 0fi
done
3.引号的特殊用法
关键要点总结:
单引号: 所有字符原样输出,不进行任何替换
双引号: 允许变量替换和命令替换,保护空格和特殊字符
反引号`: 命令替换,但推荐使用 $()
转义字符: 使用 \ 来转义特殊字符
引号嵌套: 混合使用单双引号来处理复杂情况
数组和参数: 总是用双引号引用变量,特别是包含空格的变量
#!/bin/bashecho "=================================================="
echo " Shell引号特殊用法详解脚本"
echo "=================================================="
echo# 1. 单引号 - 完全原样输出
echo "1. 单引号用法 - 完全原样输出:"
echo '单引号内的所有字符都保持原样: $HOME `date` "hello"'
echo# 2. 双引号 - 允许变量和命令替换
echo "2. 双引号用法 - 允许变量和命令替换:"
name="Shell用户"
echo "Hello, $name! 当前用户: $USER, 时间: $(date '+%H:%M:%S')"
echo# 3. 反引号 - 命令替换(推荐使用$()代替)
echo "3. 反引号用法 - 命令替换:"
echo "当前目录文件列表: `ls | head -3`"
echo "等价写法: $(ls | head -3)"
echo# 4. 转义字符 - 特殊字符处理
echo "4. 转义字符用法:"
echo "这是一个换行符: 第一行\n第二行\t带制表符"
echo -e "使用-e选项解析转义: 第一行\n第二行\t带制表符"
echo# 5. 引号嵌套使用
echo "5. 引号嵌套使用:"
echo "双引号内包含单引号: \"这是一个'单引号'在双引号内\""
echo '单引号内包含双引号: '\''这是一个"双引号"在单引号内'\'
echo# 6. 变量中的引号处理
echo "6. 变量中的引号处理:"
file_list="file1.txt file2.txt 'special file.txt'"
echo "文件列表: $file_list"
# 正确处理带空格的文件名
for file in $file_list; doecho " 文件: $file"
done
echo# 7. Here Document 中的引号
echo "7. Here Document 用法:"
cat << EOF
这是一个Here Document示例
变量不会被替换: \$HOME = $HOME
可以包含多行内容
EOF
echo# 8. Here Document 带引号
echo "8. 带引号的Here Document:"
cat << 'EOF'
这个Here Document使用单引号
变量完全原样: $HOME
命令也不会执行: $(date)
EOF
echo# 9. 引号在函数参数中的使用
echo "9. 函数参数中的引号使用:"process_args() {echo "参数个数: $#"local i=1for arg in "$@"; doecho " 参数$i: $arg"((i++))done
}echo "不带引号传递参数:"
process_args hello world with spacesecho "带引号传递参数:"
process_args "hello world" "with spaces" "special\"char"
echo# 10. 引号在数组中的使用
echo "10. 数组中的引号使用:"
files=("normal.txt" "file with spaces.txt" "special'quote.txt")echo "数组内容:"
for file in "${files[@]}"; doif [ -e "$file" ] || touch "$file" 2>/dev/null; thenecho " 文件: $file - 创建成功"elseecho " 文件: $file - 创建失败"fi
done
echo# 11. 引号在条件判断中的使用
echo "11. 条件判断中的引号使用:"
test_string="hello world"if [ "$test_string" = "hello world" ]; thenecho "字符串匹配成功"
elseecho "字符串匹配失败"
fi# 处理可能为空的变量
empty_string=""
if [ -z "$empty_string" ]; thenecho "空字符串检测成功"
fi
echo# 12. 引号在命令执行中的重要性
echo "12. 命令执行中的引号重要性:"
echo "创建测试文件..."
echo "test content" > "test file.txt"echo "不加引号(会出错):"
ls -l test file.txt 2>&1 | head -1echo "加引号(正确):"
ls -l "test file.txt"
echo# 13. 特殊字符处理
echo "13. 特殊字符处理:"
special_chars='$`\"!@#$%^&*()'
echo "特殊字符: $special_chars"
echo '单引号中的特殊字符: $`\"!@#$%^&*()'
echo# 14. 实际应用示例 - 查找文件
echo "14. 实际应用 - 文件查找:"
find . -name "*.txt" -type f -exec echo "找到文件: '{}'" \; 2>/dev/null | head -3
echo# 15. 实际应用示例 - JSON处理
echo "15. 实际应用 - JSON字符串处理:"
json_data='{"name": "John", "age": 30, "city": "New York"}'
echo "JSON数据: $json_data"
# 使用jq解析(如果已安装)
if command -v jq &> /dev/null; thenecho "$json_data" | jq '.name'
elseecho "jq命令未安装,跳过JSON解析演示"
fi
echo# 清理临时文件
cleanup() {rm -f "test file.txt" "normal.txt" "file with spaces.txt" "special'quote.txt"echo "临时文件已清理"
}cleanupecho "=================================================="
echo " 演示结束"
echo "=================================================="
4.特殊用法
①特殊变量
Shell脚本中$*和$@的区别
不加引号时:$* 和 $@ 行为相同
加双引号时:"$*":所有参数合并为一个字符串"$@":每个参数保持独立
在循环中:使用 "$@" 可以正确处理带空格的参数
最佳实践:在需要保留参数原样时,总是使用 "$@"
$*:将所有参数作为一个整体字符串处理
$@:将每个参数作为独立的字符串处理
#!/bin/bashecho "=== 演示 \$* 和 \$@ 的区别 ==="
echo# 设置一些测试参数
set -- "arg 1" "arg 2" "arg 3"echo "参数列表: $@"
echo "参数个数: $#"
echoecho "1. 直接使用 \$* 和 \$@:"
echo "使用 \$*: $*"
echo "使用 \$@: $@"
echoecho "2. 在双引号中使用:"
echo "使用 \"\$*\": \"$*\""
echo "使用 \"\$@\": \"$@\""
echoecho "3. 使用for循环遍历 \$*:"
echo -n " "
for arg in $*; doecho -n "[$arg] "
done
echo
echoecho "4. 使用for循环遍历 \$@:"
echo -n " "
for arg in $@; doecho -n "[$arg] "
done
echo
echoecho "5. 使用for循环遍历 \"\$*\":"
echo -n " "
for arg in "$*"; doecho -n "[$arg] "
done
echo
echoecho "6. 使用for循环遍历 \"\$@\":"
echo -n " "
for arg in "$@"; doecho -n "[$arg] "
done
echo
echoecho "7. 显示参数个数:"
echo " 参数总数: $#"
echo " \$* 作为整体时的参数个数: 1"
echo " \$@ 拆分时的参数个数: $#"
echoecho "8. 实际应用示例:"
echo " 将参数传递给另一个函数"# 定义一个测试函数
test_function() {echo " 在函数内参数个数: $#"echo " 在函数内参数列表: $@"
}echo " 使用 \"\$*\" 传递:"
test_function "$*"echo " 使用 \"\$@\" 传递:"
test_function "$@"
5.expr表达式
6.test命令
①test文件
②逻辑处理
[yt@localhost ~]$ [ -e /etc/passwd ]
[yt@localhost ~]$ echo $?
0
[yt@localhost ~]$ [ -e /etc/passwd -a -e /etc/group ]
[yt@localhost ~]$ echo $?
0
[yt@localhost ~]$ [ -e /etc/passwd -a -e /etc/groupp ]
[yt@localhost ~]$ echo $?
1
[yt@localhost ~]$ [ -e /etc/passwd -o -e /etc/groupp ]
[yt@localhost ~]$ echo $?
0
[yt@localhost ~]$ [ ! -e /etc/passwd ]
[yt@localhost ~]$ echo $?
1