记录Linux

1、Shell

1.1、打印方法

bash 复制代码
# 简单打印
echo "Hello World"
echo "a\nb"

# 打印变量
name="Tom"
echo "Hello, ${name}"

# 打印转义字符
echo -e "a\nb"

# 打印linux命令输出
date
ls -l

# 多行打印
cat << EOF
aaa bbb ccc ddd eee fff
111 222 333 444 555 666
变量值:${name}
EOF

# 重定向到文件
echo "hello" > out.txt      # 覆盖
echo "world" >> out.txt     # 追加
bash 复制代码
# 将 多行内容 定向到文件 abcd.log 中
name="Tom"

# 多行打印
cat << EOF  >> abcd.log
aaa bbb ccc ddd eee fff
111 222 333 444 555 666
变量值:${name}
EOF

1.2、变量

bash 复制代码
####################### 变量定义 #######################
# 等号两边绝对不能有空格!
name="Tom"
age=18
path="/home/work"

# 如果变量内容包含空格,必须用引号括起来
msg="Hello World"

# 打印变量 强烈建议使用 ${变量名} 的格式
echo ${name}
echo ${age}
echo ${path}
echo ${msg}


####################### 修改变量 #######################
# 重新复制即可
name="Jerry"
echo ${name}


####################### 删除变量 #######################
unset name
echo ${name}    # 打印为空


####################### 只读变量 #######################
readonly PI=3.14


####################### 全局变量(环境变量) #######################
export MY_VAR="hello word"
bash 复制代码
####################### 坑1 等号两边不能有空格 #######################
name = "Tom"      # Shell 会以为你在执行一个叫 name 的命令,参数是 = 和 "Tom"


####################### 坑2 单引号 '' vs 双引号 "" #######################
# 双引号 "" 弱引用,会解析里面的变量和命令。
name="Tom"
echo "Hello $name"       # 输出:Hello Tom

# 单引号 '' 强引用,里面写什么就输出什么,绝对不解析。
name="Tom"
echo 'Hello $name'       # 输出:Hello $name

# 反引号 ` 或 $() 用于执行命令并获取结果。
now=$(date)              # 推荐写法
echo "现在时间是 $now"


####################### 坑3 变量默认是字符串,不能直接算数 #######################
a=1
b=2
echo $a+$b               # 错误运用,输出 1+2 (当成字符串拼接了)

# 正确的数学运算方式:
echo $((a + b))          # 输出:3
# 或者
echo $(expr $a + $b)     # 输出:3 (注意 expr 的加号两边必须有空格)


####################### 坑4 变量引用遇到特殊字符 #######################
# 如果变量的值包含特殊字符(如 *、空格),在引用时加上双引号,否则会被 Shell 解析成通配符或被截断。
file="my file.txt"
cat $file                # 会报错,认为你要打开 "my" 和 "file.txt" 两个文件
cat "$file"              # 正确


####################### 坑5 Here Document (<<EOF) 中的变量解析 #######################
# 使用 <<EOF 时,里面的 $变量 会被解析。
# 使用 <<'EOF'(给 EOF 加上单引号)时,里面的 $变量 不会被解析,原样输出。
name="Tom"
cat << 'EOF'
aaa bbb ccc ddd eee fff
111 222 333 444 555 666
变量值:${name}
EOF


####################### 坑6 未定义变量的处理 #######################
# 如果你引用了一个没定义过的变量,默认会输出空(不会报错),这可能导致灾难性后果。
# 推荐在脚本开头加上 set -u,这样一旦用到未定义的变量,脚本会立刻报错退出,防止误删数据。
# 或者使用默认值语法:${name:-默认值}(如果 name 没定义,则返回"默认值")。
set -u
cat << EOF
aaa bbb ccc ddd eee fff
111 222 333 444 555 666
变量值:${name}
EOF

1.3、循环

bash 复制代码
####################### for循环 #######################
# 形式一  遍历列表
for 变量 in 列表
do
    命令
done

# 形式二  C 语言风格(常用于精确控制次数)
for ((初始值; 条件; 步长))
do
    命令
done


####################### for循环举例 #######################
for file in *.log
do
    echo "正在备份文件: $file"
    cp "$file" "${file}.bak"
done

aaa=("1111" "2222" "3333" "4444")
for st1 in "${aaa[@]}"
do
    echo ${st1}
done

for ((i=0;i<10;i++))
do
    echo ${i}
done
# "${aaa[@]}" 展开数组所有元素,加双引号可以应对元素带空格的场景,是最佳实践;
# 如果写 ${aaa[*]} 会把所有元素合并成一整个字符串;
bash 复制代码
####################### while循环 #######################
# 只要条件成立(真),就一直循环执行。适合不知道要循环多少次,只知道达成某个条件就停止的场景。
while [ 条件判断 ]
do
    命令
done


####################### while循环举例 #######################
# 逐行读取out.txt文件
while IFS= read -r line
do
    echo "读取到内容: $line"
done < "out.txt"

i=10
while [ ${i} -lt 11 ]       # 判断 i 小于 11
do
    echo "aaaaaa"
    i=$((i + 1))
done
bash 复制代码
####################### until循环 #######################
# 和 while 刚好反过来。只要条件不成立(假),就一直循环;一旦条件成立(真),立刻停止。适合"直到...才停止"的逻辑。
until [ 条件判断 ]
do
    命令
done


####################### until循环举例 #######################
# 实例 等待 MySQL 服务完全启动
until systemctl is-active --quiet mysqld
do
    echo "MySQL 还没启动,等 2 秒再试..."
    sleep 2
done
echo "MySQL 已启动!"
bash 复制代码
####################### select循环 #######################
select 变量 in 选项1 选项2
do
    命令
done


####################### select循环举例 #######################
PS3="请选择要执行的操作: "
select action in "启动服务" "停止服务" "重启服务" "退出"
do
    case $action in
        "启动服务") echo "正在启动..."; break ;;
        "停止服务") echo "正在停止..."; break ;;
        "退出") exit 0 ;;
        *) echo "无效选择,请重新输入" ;;
    esac
done

# 坑点: 没有退出机制; 如果没有写 break 或 exit,Ctrl+C 退出后如果不小心按了回车,还会继续循环。通常需要配合 case 语句使用

1.4、函数

bash 复制代码
####################### 定义 #######################
# 方式一 推荐
函数名() {
    命令
}

# 方式二 使用 function 关键字(更适合习惯其他语言的人)
function 函数名 {
    命令
}


####################### 调用 #######################
# 实例演示
say_hello() {
    echo "Hello, 欢迎学习 Shell!"
}
# 调用函数
say_hello
bash 复制代码
####################### 函数传参 #######################
is_even() {
    # 检查参数个数是否为 1 个
    if [ $# -ne 1 ]; then
        echo "错误:需要提供一个参数!"
        return 1 # 返回错误状态码
    fi

    if (( $1 % 2 == 0 )); then
        return 0  # 成功/代表真
    else
        return 1  # 失败/代表假
    fi
}

is_even 4
if [ $? -eq 0 ]; then
    echo "4 是偶数"
fi

1.5、想在一个shell脚本中,同时启动多个字进程

bash 复制代码
# Shell 中的进程主要分为以下几种情况
#     前台进程 (Foreground):默认情况,你敲下命令,终端被这个进程霸占,直到它执行完,你才能敲下一个命令。
#     后台进程 (Background):在命令末尾加 &,进程会在后台偷偷跑,终端立刻还给你,你可以继续敲别的命令。
#     子 Shell (Subshell):使用 (命令) 或 | 管道符,或者执行另一个脚本 ./test.sh 时,会 fork 出一个子进程(子 Shell)。子 Shell 会继承父 Shell 的变量,但子 Shell 里的修改不会影响父 Shell。(这就是前面提到的"管道陷阱"的根源)。


常用进程控制命令:
    &               放到后台执行。
    jobs            查看当前终端后台的任务。
    fg %1           把后台第 1 个任务调回前台。
    bg %1           把暂停的任务放到后台继续跑。
    wait            等待所有后台子进程结束。
    $!              获取最后一个后台进程的 PID(进程号)。
    kill -9 PID     强杀进程。
bash 复制代码
#!/bin/bash
# =============================================================================
# process_demo.sh
# 并行跑两个循环,打印各自 PID;两个循环没跑完,主进程就不退出
# =============================================================================

# 循环1:每 10 秒 +1,从 1 加到 100
loop1() {
    local n=1                          # 局部变量 n,初始值 1(local 保证只在函数内有效)
    while [ "$n" -le 100 ]; do         # 当 n <= 100 时循环(-le 表示小于等于)
        echo "[循环1 pid=$$] n = $n"    # 打印当前值;$$ 是脚本进程号
        n=$((n + 1))                   # n 加 1,$(( )) 是算术运算
        sleep 10                       # 暂停 10 秒再进入下一轮
    done
}

# 循环2:每 20 秒 +10,从 1000 加到 2000
loop2() {
    local m=1000                       # 局部变量 m,初始值 1000
    while [ "$m" -le 2000 ]; do        # 当 m <= 2000 时循环
        echo "[循环2 pid=$$] m = $m"    # 打印当前值
        m=$((m + 10))                  # m 加 10
        sleep 20                       # 暂停 20 秒再进入下一轮
    done
}

# 后台并行启动两个循环,用 $! 分别捕获 PID
loop1 &                                # & 把 loop1 丢到后台执行,不阻塞往下走
PID1=$!                                # $! = 最近一个后台进程的 PID,立刻存进 PID1

loop2 &                                # loop2 也丢到后台,与 loop1 并行
PID2=$!                                # 此刻 $! 变成 loop2 的 PID,存进 PID2

echo "循环1 PID = $PID1"               # 打印两个后台进程各自的 PID
echo "循环2 PID = $PID2"

# 主进程等待两个后台循环,期间不退出;两者都结束后主进程才退出
wait                                   # 不带参数:阻塞直到所有后台子进程结束
相关推荐
额额额对了1 小时前
嵌入式 Linux 实战:i.MX6ULL 上的 CAN 通信与摄像头采集
linux·运维·服务器
牛马鸡niumasi1 小时前
【Linux】进程替换
linux
灯澜忆梦2 小时前
【Linux】#10 | Linux 终端实用快捷键 + 安装应用
linux·运维·服务器
码士集团小青2 小时前
面霸篇:高频 Java 基础问题(核心卷一)
linux·服务器·数据库·redis·缓存·1024程序员节
水饺编程3 小时前
第2章:Linux 基础,切换用户
linux·c语言·汇编
Lsetea4 小时前
curl指定--tlsv1.2仍连接TLS1.3:最低版本与tls-max排查
linux·https·ssl证书·curl·tls
Lsetea4 小时前
curl访问HTTPS报47 Too many redirects:重定向循环与max-redirs排查
linux·http·https·ssl证书·curl
9624565 小时前
一次 Dell PowerEdge R750xs 启动故障复盘:从 iDRAC 带外管理到 Linux 多内核回退与 initramfs 重建
linux·运维·服务器
Zevalin爱灰灰6 小时前
Linux入门第一部分(Ubuntu入门篇) 第二章 浅尝Ubuntu(二)
linux·嵌入式·1024程序员节