FFmpeg (二) shell echo 数组

2 阅读3分钟

一、Shell 基础概念

1. 什么是 Shell

Shell 是命令行解释器,负责翻译用户命令 → 内核执行 → 返回结果。

Shell 脚本:批量编写多条命令,实现自动化运维。

常见解释器:bash(Linux 默认)、zsh(Mac 默认)、sh

脚本后缀 .sh 仅为标识,不决定能否执行。

2. 查看当前 Shell(Mac 必看)

# 查看默认登录 Shell
echo $SHELL

# 查看当前真实运行 Shell
ps -p $$

⚠️ $SHELL 是用户默认 Shell,不会随脚本执行器改变!

3. 第一个脚本 HelloWorld

脚本规范首行(幻数)

#!/bin/bash
echo "Hello World"

含义:指定用 bash 解释器执行脚本,必须在第一行。

三种执行方式

  1. bash hello.sh / zsh hello.sh:无需执行权限,强制指定解释器(会忽略脚本第一行幻数)
  2. sh hello.sh:使用系统默认 sh 执行
  3. chmod +x hello.sh 加权限后 ./hello.sh:读取脚本第一行幻数执行

⚠️ ./ 不能省略,代表当前目录。

二、Shell 注释语法

1. 单行注释

# 单行注释
echo "test" # 行尾注释

2. 多行注释

:<<EOF
这里是多行注释
可以写任意内容
EOF

EOF 为自定义标记,首尾必须一致。

三、Shell 变量(高频易错)

1. 变量定义规范

✅ 正确:name="zhangsan"

❌ 错误:name = "zhangsan"(等号绝对不能有空格)

2. 变量调用

echo $name
echo ${name} # 推荐,边界更清晰

3. 变量分类

  • 自定义变量:仅当前 Shell 进程有效
  • 环境变量:全局所有进程有效,env 查看

4. 只读变量

readonly age=20
age=30 # 报错,不可修改

5. 删除变量

unset name

⚠️ readonly 只读变量无法 unset 删除

6. 变量类型特性

Shell 是弱类型语言:所有变量默认都是字符串。

整数运算必须用:$(( ))

a=10
b=20
c=$((a+b))
echo $c

四、字符串操作(必考)

1. 三种定义方式

str1=hello
str2="hello world"
str3='hello shell'

2. 单引号 / 双引号区别

  • 单引号 '' :原样输出,不解析变量
  • 双引号 "" :解析 $ 变量,支持转义
name=jack
str1='hi $name'  # 输出 hi $name
str2="hi $name"  # 输出 hi jack

3. 字符串长度

str="abcd"
echo ${#str} # 4

4. 字符串截取

语法:${str:起始下标:截取长度}(下标从 0 开始)

str="abcdefg"
echo ${str:0:3} # abc
echo ${str:2}  # cdefg

5. 字符串拼接

直接拼接,无需加号

a="hello"
b="world"
c="${a}${b}"

6. 字符串替换

str="aaabbbccc"
echo ${str/aaa/xxx}  # 替换第一个
echo ${str//b/BB}   # 全部替换

五、echo 输出

echo "hello"     # 自动换行
echo `date`       # 输出系统时间

六、数组

正确定义(❌ 不能用逗号)

# 正确:空格分隔
arr=("张三" "李四" "坦克")

echo ${arr[0]}       # 取单个
echo ${arr[@]}       # 取所有
echo ${#arr[@]}      # 数组长度
echo ${#arr[2]}      # 单个元素长度

七、脚本参数

echo $0   # 脚本名
echo $#   # 参数个数
echo $*   # 所有参数

八、运算符大全

1. 算术运算两种方式

方式1:$(( ))(推荐)

a=100
b=200
echo $((a+b))
echo $((a-b))
echo $((a*b))
echo $((a%b))

方式2:expr(必须空格、*需转义)

expr $a + $b
expr $a * $b

2. 比较、逻辑运算

echo $((a < b))
echo $((a > b))
echo $((a == b))
echo $((a != b))
echo $((a && b))
echo $((a || b))

九、文件测试运算符(A-Z 完整版 + 纠错)

⚠️ -n -z只判断字符串,不能判断文件!

⚠️ -h -L 都是软链接,没有判断硬链接的参数!

运算符含义
-a/-e文件/目录是否存在
-d是否为目录
-f是否为普通文件
-r文件可读
-w文件可写
-x文件可执行
-s文件存在且非空
-h/-L软链接文件
-b块设备
-c字符设备
-n字符串非空
-z字符串为空

十、流程控制(全部修正错误写法)

1. if 判断

if [ 条件 ]; then
  逻辑
elif [ 条件 ]; then
  逻辑
else
  逻辑
fi

2. for 循环(三种正确写法)

写法1:区间遍历

for i in {1..10}
do
  echo $i
done

写法2:数组遍历

arr=(1 2 3 4 5)
for i in ${arr[@]}
do
  echo $i
done

写法3:C 语言风格(必须双层括号)

sum=0
for ((i=1;i<=10;i++))
do
  sum=$((sum+i))
done
echo $sum

重点纠错

❌ 错误:for(i=1;i<=10;i++)

✅ 正确:for ((i=1;i<=10;i++))

❌ 错误:for i in ("a","b")(Shell 不用逗号)

✅ 正确:for i in "a" "b"

3. while 循环

sum=0
i=1
while [ $i -le 10 ]
do
  sum=$((sum+i))
  i=$((i+1))
done
echo $sum

4. case 分支

i=1
case $i in
    1) echo "是1";;
    2) echo "是2";;
    *) echo "其他";;
esac

十一、文件导入与 bc 计算器

1. 导入其他脚本

source ./hello.sh
# 或
. ./hello.sh

2. bc 浮点运算

res=$(echo "1.2+2.3" | bc)
echo $res

十二、重定向 & 文件描述符(核心重难点)

1. 三大默认文件描述符

  • 0 标准输入 stdin(键盘)
  • 1 标准输出 stdout(屏幕)
  • 2 标准错误 stderr(屏幕)

2. 四大重定向符号

  • > 输出覆盖(清空文件写入)
  • &gt;&gt; 输出追加(末尾新增)
  • < 输入重定向(文件代替键盘输入)
  • << HereDoc 多行输入

3. 输入重定向 <

wc -l < /etc/passwd

# 逐行读取文件
while read line
do
  echo $line
done < test.txt

4. 多行重定向 <<EOF

cat <<EOF
第一行内容
第二行内容
EOF

# 直接写入文件
cat > out.txt <<EOF
内容
EOF

⚠️ 结束标记必须顶格无空格

5. 标准输出、错误输出分离/合并

# 分开保存
ls /etc /no 1>ok.log 2>err.log

# 合并保存(顺序不能反)
ls /etc /no > all.log 2>&1
ls /etc /no &> all.log

6. 临时重定向 VS 永久重定向 exec

  • 命令 > file:仅当前命令生效
  • exec 1>file:后续所有命令永久重定向

7. 自定义文件描述符(10 以上)

# 只读打开
exec 11< test.txt
read -u 11 str
exec 11<&-

# 读写打开
exec 12<> test.txt
read -u 12 a
echo "hi" >&12
exec 12<&-

8. 重定向备份与恢复

exec 13<&1    # 备份屏幕输出
exec 1> log.txt
echo "写入日志"
exec 1<&13    # 恢复屏幕
exec 13<&-    # 关闭fd

9. 屏蔽输出 /dev/null

命令 > /dev/null 2>&1

十三、临时文件 & 日志实战

1. mktemp 安全临时文件

tmp=$(mktemp /tmp/xxx.XXXXXX)
trap 'rm -f $tmp' EXIT # 退出自动删除

2. 日志函数(工程常用)

log(){
  echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a run.log
}

十四、全书高频踩坑汇总(必背)

  1. 变量赋值 a=1 等号不能有空格
  2. for C 循环必须 (( )) 双层括号
  3. 数组、for-in 遍历只用空格分隔,不用逗号
  4. $SHELL 不代表当前脚本解释器
  5. 重定向合并 >file 2>&1顺序不能反
  6. 自定义 fd 必须 10 以上,用完必须关闭
  7. -n -z 只判断字符串,不判断文件
  8. HereDoc 结束标记必须顶格