迟来的第二篇!其实我早就写好了,忘记发了
这一篇还是挺重要的,包括$符号、重定向等等,算是解决了之前看别人写的命令的很多疑惑
第一篇看这里:Linux命令(文件管理篇)
echo —— 在终端显示一行文本或变量
主要功能是将紧跟在它后面的字符串或变量的值输出到标准输出
语法格式
echo [参数] <字符串>
Shell的解析
echo在实际执行之前,Shell会先对命令行进行解析,处理各种扩展规则
这使得echo的行为不仅取决于它的参数内容,还取决于这些参数是如何写的
命令解析顺序
Shell 在执行echo命令之前,会按照以下顺序解析命令行内容:
- 变量替换,例如
$USER、$HOME等会被替换成当前环境中相应的值 - 命令替换,例如
$(date)或date会被替换为命令执行后的输出结果 - 路径通配符,如
*.txt - 引号的解析和空格的处理
关于$使用方法移步:[$符号的使用](#echo扩展:$ —— Shell中的特殊元字符)
使用双引号 " " —— 弱引用
双引号内部的内容保留大部分字面意义,但允许进行变量和命令替换
echo "Hello $USER, today is $(date)"
$USER被替换成当前用户名,$(date)被替换成当前系统时间,输出结果可能是:
Hello bob, today is Tue Jul 30 20:00:00 JST 2025
双引号还可以保留字符串中的空格,例如:
echo "Hello World"
会输出:
Hello World
使用单引号 ’ ’ —— 强引用
单引号内部的所有内容都按字面含义处理,禁止任何形式的变量和命令替换
echo 'Hello $USER, today is $(date)'
输出结果为:
Hello $USER, today is $(date)
即完全照原样输出,不做任何解析
不使用引号
不加引号的参数会被Shell正常解析,包括变量和命令替换,但有两个值得注意的特点:
- 多个空格会被压缩为一个
- 如果参数中有特殊字符或空格,Shell会认为它们是分隔符或命令符号
echo Hello $USER
输出类似:
Hello bob
空格被压缩了,只显示一个空格
常用参数
核心功能
| 参数 | 功能说明 |
|---|---|
| -n | 不在末尾输出自动的换行符 |
| -e | 启用对反斜杠转义字符的解释,例如,\n会被解释为换行,\t会被解释为制表符 |
| -E | 显式地禁用对反斜杠转义字符的解释(通常是默认行为) |
使用示例
-
显示简单的文本字符串
echo "Hello, Linux World!" -
使用转义字符进行格式化输出
echo -e "Files found:\n\t- /path/to/file1.txt\n\t- /path/to/file2.txt"输出:
Files found: - /path/to/file1.txt - /path/to/file2.txt
echo扩展:$ —— Shell中的特殊元字符
$符号本身并不是一个命令,而是Linux Shell中的一个特殊元字符
它的核心功能是进行扩展,即将其后面的内容替换成别的值,例如变量的值或命令的执行结果
变量引用
引用普通变量
name="linux"
echo $name
上面的命令将会输出linux
引用环境变量
echo $HOME # 当前用户的主目录
echo $HOSTNAME # 当前主机名
echo $PATH # 可执行程序搜索路径,即/bin和/sbin
echo $SHELL # 默认shell类型
echo $USER # 当前用户名
echo $UID # 当前用户ID
顺便提一嘴,查看环境变量有哪些可以使用printenv、env、set
避免歧义
${}的写法在变量名后紧跟其他字符时可避免歧义:
echo ${name}123
上面的命令将会输出linux123
命令替换
使用$()
echo $(date)
先执行date命令,再将其输出替换到echo
使用反引号
echo `date`
推荐使用$(),因为可嵌套
算术扩展
使用双重括号(())包裹表示算术表达式:
$((表达式))
可进行整数运算:
echo $((1+2))
上面的命令将会输出输出3
也可以定义变量:
x=5
echo $((x*2))
上面的命令将会输出10
特殊变量
Shell内置有很多特殊变量,用$引用,一般在脚本里面使用,方便脚本编写:
| 变量名 | 含义说明 | 示例值 / 用法 |
|---|---|---|
$0 |
当前脚本的名称 | ./myscript.sh |
$1~$9 |
脚本的第1到第9个参数 | $1是第1个参数 |
${10} |
第10个及以上的参数,必须使用大括号 | ${10} |
$# |
传递给脚本的参数个数 | 3 表示有三个参数 |
$@ |
以独立字符串形式表示所有参数 | "arg1" "arg2" "arg3" |
$* |
以一个整体字符串形式表示所有参数 | "arg1 arg2 arg3" |
$$ |
当前Shell进程的PID | 13542 |
$! |
最近一次后台运行的进程PID | 18321(如sleep 10 &后的进程号) |
$? |
上一条命令的退出状态(0 表示成功,非 0 失败) | 0表示成功,1表示失败 |
$- |
当前Shell启动时使用的选项 | 如himBH表示启用了哪些选项 |
$_ |
上一条命令中的最后一个参数 | 比如刚运行cp file1 file2,则为file2 |
字符串处理
$结合{}可进行多种扩展操作:
默认值处理
| 表达式 | 含义 |
|---|---|
${var:-word} |
如果var未设置或为空,返回word |
${var:=word} |
如果var未设置或为空,返回word并将其赋值给var |
${var:?message} |
如果var未设置或为空,输出message到标准错误,并中止脚本 |
${var:+word} |
如果var设置了值,返回word,否则返回空 |
eg:
echo ${var:-default}
var未定义或为空时输出default
字符串长度
语法:
${#变量名}
这是一种字符串长度计算语法,会计算变量名中字符串的字符数
eg:
str="linux"
echo ${#str}
上面的命令会输出5
子串截取
语法:
${变量名:起始位置:长度}
${变量名:起始位置}
- 起始位置0开始计数
- 若不指定长度,则截取到末尾
- 若起始位置为负数,从右往左数
eg:定义字符串str="linuxsystem"
echo ${str:0:5}
输出linux,从位置0开始,截取5个字符
echo ${str:5}
输出system,从位置5开始截到末尾
子串删除
| 语法 | 含义 |
|---|---|
${变量%模式} |
从变量值末尾开始,删除最短匹配的 模式 |
${变量%%模式} |
从变量值末尾开始,删除最长匹配的 模式 |
${变量#模式} |
从变量值开头开始,删除最短匹配的 模式 |
${变量##模式} |
从变量值开头开始,删除最长匹配的 模式 |
eg:
path="/home/user/file.txt"
echo ${path%/*} :输出/home/user
echo ${path##*/} :输出file.txt
cat —— 连接文件并打印到标准输出
cat命令是Linux中一个非常基础且功能强大的文本文件处理工具
它的名称是concatenate(连接)的缩写,其核心功能是将一个或多个文件的内容连接起来,并将其输出到标准输出(通常是终端屏幕)
语法格式
cat [参数] <文件名1> <文件名2>...
Linux标准输入输出与重定向
标准输入输出
在Linux中,命令运行时默认会关联三个数据流:
- 标准输入(stdin):命令获取数据的默认来源,一般是键盘输入,文件描述符为0
- 标准输出(stdout):命令输出结果的默认目的地,一般是终端屏幕,文件描述符为1
- 标准错误(stderr):命令的错误信息输出的默认目的地,也是终端屏幕,文件描述符为2
例如执行cat file.txt,程序会从标准输入中读取文件内容并写到标准输出,因此屏幕上可以看到结果
使用&+文件描述符,可以表示对应输入输出的位置,比如&1就是标准输出当前所在的位置,类似指针
重定向操作符
重定向是指把命令的标准输入或标准输出指向到其他位置(如文件),常见用法包括:
-
>:把命令的标准输出重定向到指定文件,如果文件存在,会覆盖原内容,默认作用于标准输出(stdout)echo "Hello" > test.txt上面命令会把字符串写入
test.txt,覆盖其原有内容因为>默认作用于stdout,也就是说平时代表标准输入的1省略了,他等价于:
echo "Hello" 1> test.txt注意
1和>之间不能有任何空格,否则会被解析成echo后字符串的一部分,对于0和2也是一样还可以使用空的内容重定向文件,快速做到清除文件:
> test.txt经过我的测试,这个效果和
cat > test.txt一样,执行之后要手动ctrl+c退出,不然输入的内容就写进去了,或许不同系统有不同效果吧 -
>>:把命令的标准输出以追加方式重定向到指定文件,不会覆盖原内容echo "World" >> test.txt上面命令会把字符串追加到
test.txt的末尾 -
<:把标准输入重定向为某个文件内容cat < test.txt上面命令会从
test.txt读取数据作为标准输入并显示在屏幕,结果上等同于cat test.txt不过我们一般不这样使用,而是结合其他命令:
sort < test.txt上面命令会对
test.txt内容排序后输出 -
<<:启动多行输入模式(HereDocument)cat << EOF上面命令会把接下来的多行内容作为标准输入,直到遇到
EOF标识符,这个标识符是自己定义的 -
2>:把命令的标准错误流(stderr)重定向到指定文件,如果文件存在,会覆盖原内容ls nofile.txt 2> error.log上面命令会把
ls的错误信息写入到error.log文件中,而不是显示在屏幕上 -
2>>:把命令的标准错误流以追加方式重定向到指定文件,不会覆盖原内容ls nofile.txt 2>> error.log上面命令会把错误信息追加到
error.log文件末尾 -
2>&1:把标准错误重定向到标准输出的位置(合并到一起)yourcommand > log 2>&1上面命令会把标准输出和标准错误都写入到
log文件中(先把标准输出重定向到log,再把标准错误重定向到标准输出,也是log)同样的,
>和&1之间不能有空格,否则&1会被当成文件名处理 -
&>:同时重定向标准输出和标准错误流到指定文件yourcommand &> log上面命令也会把标准输出和标准错误都写入到
log文件中,一步到位,但只在bash或zsh等兼容shell中有效,老的sh不支持
上面我们提到的重定向都是针对当前的命令,如果想要对整个当前shell都生效,必须用exec重定向:
exec &> log
这样之后在这个shell里的所有输出都会写进log,直到恢复或退出
常用参数
| 参数 | 功能说明 |
|---|---|
| -n | 从1开始为所有输出行编号 |
| -b | 与-n类似,但只为非空行编号 |
| -s | 当遇到有连续两行以上的空白行,就代换为一行的空白行 |
| -E | 在每行结束处显示一个$符号 |
| -T | 将Tab制表符显示为^I |
| -v | 显示不可打印字符(除了换行符和 Tab) |
| -e | 等价于-vE:显示不可见字符,行尾加$ |
| -A | 等价于-vET:显示不可见字符,行尾加$,Tab制表符显示为^I |
使用示例
-
同时查看并合并多个文件的内容
cat file1.txt file2.txtcat会按照参数顺序,将file1.txt和file2.txt的内容连续地打印到屏幕上 -
创建新文件
cat > new_file.txt # 执行该命令后,光标会停留在下一行等待输入 # 输入想要的内容,例如: Hello, world.This is a new file. # 按下 Ctrl + C 组合键来保存并退出这里
cat因为没有指定文件名,所以从键盘(标准输入)读取内容,而>将这些内容重定向到了new_file.txt文件中也可以使用
<<指定标识符:cat > file.txt << END # 输入想要的内容,例如: Hello World END # file.txt的内容会变成: Hello World -
合并多个文件为一个新文件
cat part1.log part2.log > full.log -
向文件末尾追加内容
cat >> file.txt # 输入内容 # 按下 Ctrl + C 结束也可以使用
<<指定标识符:cat >> file.txt << END -
显示文件内容并附带行号
cat -n file
tac —— 逆序连接并打印文件内容
tac的名称非常直观,就是cat命令的反写,核心功能也与cat正好相反:cat从第一行开始正序显示文件内容,而tac则从最后一行开始逆序显示文件内容
语法格式
tac [参数] <文件名>
tac的基本执行流程
- 读取整个文件的内容
tac通常是先读取完整个文件(或标准输入)到内存中(或者内部缓冲区)
- 按分隔符拆分内容
- 默认分隔符是换行符
\n,也可以用-s指定其他分隔符 - 如果使用了
-r,分隔符则是一个正则表达式,用于匹配多种分隔符 tac会把文件内容按照分隔符切分成若干“块”
- 默认分隔符是换行符
- 倒序输出这些块
- 按块的顺序从最后一个块开始输出到第一个块
- 在每两个块之间加上分隔符,默认情况下,分隔符附加在块内容的后面(块后)
- 如果加了
-b,分隔符放在块内容前
- 输出拼接成最终倒序结果
- 输出每个块以及分隔符,形成完整倒序后的文本
常用参数
不同于cat,tac的参数非常少
| 参数 | 功能说明 |
|---|---|
| -b | 在每行内容之前附加分隔符(默认为换行符) |
| -r | 将分隔符当作正则表达式来处理 |
| -s <字符串> | 使用指定的字符串作为记录分隔符,而不是默认的换行符 |
使用示例
-
tac命令的几个用法都有些难以理解,这里我们举几个具体的例子
假设我们有一个
numbers.txt文件,内容如下:One,Two Three执行
tac命令,块分割是One,Two和Three,按照块2 - 分隔符 - 块1的倒序,输出结果将会是:Three \n One,Two ↓ Three One,Two如果使用
-b参数,让分隔符输出在块之前,按照分隔符 - 块2 - 块1的顺序,输出结果将会是:\nThree One,Two ↓ ←注意这一行是\n造成的 ThreeOne,Two如果使用
tac -s ,,即使用,作为分隔符,块分割将会变成One和Two\nThree\n(注意最后一行末尾也是有换行符的),按照块2 - 分隔符 - 块1的倒序,输出结果将会是:Two\nThree\n,One ↓ Two Three ,One如果使用
-b参数,让分隔符输出在块之前,按照分隔符 - 块2 - 块1的顺序,输出结果将会是:,Two\nThree\nOne ↓ ,Two Three One -
查找文件中最后一次出现某个模式的行
tac log | grep -m 1 "ERROR"执行流程:
tac log: 首先将整个日志文件按行逆序,最新的日志现在在最上面|: 将逆序后的内容通过管道传递给grepgrep -m 1 "ERROR": 在逆序的输出中,查找第一个匹配“ERROR”的行,因为文件已经逆序,所以这个“第一个”匹配的行实际上是原始文件中的最后一个,-m 1确保grep在找到后立即停止
less & more —— 分页显示文本文件内容
less和more 是Linux中用于分页查看长文本文件的命令
当一个文件的内容超过一屏时,使用cat会瞬间刷满屏幕导致无法看清前面的内容,此时就应该使用less或more
语法格式
使用方式相同:
more/less [参数] <文件名>
从more到less的演进
more
more是Unix系统中最早的分页查看工具,意思是“更多”,表示“继续显示更多内容”
它允许用户分屏浏览文本文件或命令输出,默认一页一页地显示内容
但它的功能简单,交互有限,只能向下翻页(按空格键或回车键),不支持向上滚动回看已经滚过的内容
less
less是对more的改进版本,它其实是开玩笑地取名,含义是“less is more”(少即是多)
改进点:
- 支持双向滚动(上下翻页都能用)
- 支持搜索、跳转、更丰富的交互
- 处理大文件更高效,打开大文件时速度更快,因为它不会一次性将整个文件读入内存
在几乎所有的现代Linux发行版中,less已经完全取代more成为默认和推荐的分页器
交互模式下的常用按键
当我们使用less/more打开一个文件后,就进入了它的交互模式,可以使用按键进行操作
more
| 按键 | 功能 |
|---|---|
| 空格键 / f | 向下翻一页 |
| b | 向上翻一页**(部分版本支持)** |
| Enter键 | 向下滚动一行 |
| /pattern | 向下搜索字符串pattern |
less
| 按键 | 功能 |
|---|---|
| 空格键 / f | 向下翻一页 |
| b | 向上翻一页 |
| Enter键 / j / ↓ | 向下滚动一行 |
| k / ↑ | 向上滚动一行 |
| G | 直接跳转到文件末尾 |
| g | 直接跳转到文件开头 |
| d | 向下滚动半页 |
| u | 向上滚动半页 |
| /pattern | 向下搜索字符串pattern |
| ?pattern | 向上搜索字符串pattern |
| n | 跳转到下一个搜索匹配项 |
| N | 跳转到上一个搜索匹配项 |
| q | 退出less |
| h | 显示帮助菜单,列出所有可用按键 |
常用参数
more
| 参数 | 说明 |
|---|---|
| -d | 显示“按空格继续,q退出”的提示信息 |
| -c | 每次显示前清屏 |
| -s | 合并连续多个空行为一行 |
| -num | 设置每次显示的行数(如-20表示20行) |
| -f | 统计行数时,连同换行符一起计算 |
less
| 参数 | 说明 |
|---|---|
| -N | 显示行号 |
| -S | 不自动换行,横向超出屏幕的内容用→标示 |
| -X | 退出时不清屏,保留显示内容 |
| -z N | 指定滚动的页面行数N |
| -i | 搜索时忽略大小写 |
| -I | 搜索时忽略大小写,且搜索模式固定 |
| -p pattern | 启动后直接跳转到第一个匹配pattern的地方 |
| -F | 如果内容只有一屏,直接退出 less |
| -R | 显示颜色转义序列(保留颜色) |
学习过vim编辑器的肯定会发现less和vim操作有许多相似之处,也的确如此 —— 他们都是vi编辑器的后辈
什么?你还没有学过vim?点击即送免费课堂! –> vim完全使用教程
使用示例
-
查看一个长文件
less/more log -
分页查看命令输出
ls -alh /etc | less/more -
查看文件并显示行号(less独有)
less -N log -
设置每页显示的行数(more独有)
more -20 log -
在文件中进行搜索
less log操作流程:
- 使用
less打开文件后,直接按/键 - 输入想搜索的关键词(例如
ERROR),再按回车 less会高亮显示第一个匹配项,可以按n键跳转到下一个匹配项,按N键跳转到上一个
- 使用
head —— 从文件头部查看内容
与cat不同,其核心功能是显示指定文件开头的部分内容
语法格式
head [参数] <文件名>
常用参数
核心功能
| 参数 | 功能说明 |
|---|---|
| -n <行数> 或 -<行数> |
显示文件的开头N行 |
| -c <字节数> | 按字节数显示文件的开头内容,而不是按行数 |
控制与输出
| 参数 | 功能说明 |
|---|---|
| -q | 当处理多个文件时,不显示每个文件名前的头部标签 |
| -v | 总是显示文件名头部标签 |
使用示例
-
查看文件的开头10行
head file在不指定行数时,默认显示文件的开头10行
-
查看文件的开头5行
head -n 5 /etc/hosts也可以使用下面的简写形式,效果完全一样:
head -5 /etc/hosts -
查看多个文件的头部标签
head -n 3 file1.txt file2.txt当
head处理多个文件时,它会默认在每个文件的内容前显示文件名作为标题(如==> file1.txt <==),方便区分
tail —— 从文件尾部查看内容
与head命令正好相反,tail的核心功能是显示指定文件末尾的部分内容
语法格式
tail [参数] <文件名>
Linux日志监控
tail命令之所以重要,是因为它完美地契合了Linux系统管理的常见需求——日志监控
- 在Linux系统中,应用程序和系统服务的日志通常是不断增长的文本文件,最新的内容总是在文件末尾
tail命令最强大的功能之一就是能够实时地跟踪一个文件的末尾- 当新内容被追加到文件中时(例如,一条新的日志记录被写入),
tail可以立即将其显示在终端上,这使其成为系统管理员和开发者监控程序状态和排查问题的必备工具
Linux管道与命令组合
- 管道
|的作用是将前一个命令的标准输出直接作为后一个命令的标准输入 - 错误信息默认不会被传递,如果要传递错误输出,可用
2>&1合并,比如命令1 2>&1 | 命令2 head和tail命令经常在管道中组合使用,以精确地提取出文件的中间部分
常用参数
核心功能
| 参数 | 功能说明 |
|---|---|
| -n <行数> 或 -<行数> |
N是正整数:显示文件的末尾N行 N是带 +的数字:从文件第N行开始输出到文件结尾(不能使用-<行数>形式) |
| -f | **持续监控并显示文件的追加内容 **当文件增长时,新内容会实时显示出来。按 Ctrl+C退出 |
| -F | **与-f类似,但更强大 **当被监控的文件被重命名或删除后重新创建时,-F能够智能地重新打开新文件并继续监控 |
| -c <字节数> | 按字节数显示文件的末尾内容,而不是按行数 |
控制与输出
| 参数 | 功能说明 |
|---|---|
| -q | 当处理多个文件时,不显示每个文件名前的头部标签 |
| -v | 总是显示文件名头部标签 |
使用示例
-
查看文件的最后10行
tail file.txt在不指定行数时,默认显示文件的末尾10行
-
从第10行开始查看文件到结尾
tail -n +10 file.txt -
查看
error.log文件的最后100行tail -n 100 error.log也可以使用下面的简写形式,效果完全一样:
tail -100 error.log -
持续监控Nginx访问日志文件
tail -f /var/log/nginx/access.log每当有新的访问请求被记录下来,该条日志就会立即显示在终端上,按
Ctrl+C可以停止监控 -
查看一个日志文件的第101行到110行
head -n 110 log | tail -n 10head -n 110 large_file.log先取出文件的前110行内容|(管道符) 将这110行内容作为输入,传递给下一个命令tail -n 10接收到这110行内容,并从中取出最后的10行- 最终,屏幕上显示的就是原始文件的第101行到第110行
tee —— 从标准输入读取并同时写入到标准输出和文件
tee的名称来源于水管工程中的T型三通管,功能也与之类似:
它从标准输入读取数据,然后将其一分为二,一份输出到标准输出,另一份输出到一个或多个文件中
语法格式
tee命令几乎总是与管道符|结合使用,收前一个命令的输出作为自己的输入
<某个命令> | tee [参数] <文件名>
Linux管道中的“三通管”
可以把tee的处理想象一个水管的T型三通接头:
┌────> stdout(屏幕)
stdin ───┤
└────> 文件
数据流(就像水流)通过管道|流入tee命令,而tee命令就像这个三通接头,它将数据流一分为二:
- 一股水流继续沿着管道向下流,流向标准输出(您的屏幕)
- 另一股水流从T字的侧口流出,被导入到一个或多个文件中
这个特性使得我们可以在不中断管道流的情况下,既能实时查看命令输出,又能将其保存到文件中
常用参数
| 参数 | 功能说明 |
|---|---|
| -a | 追加模式,将内容追加到指定文件的末尾,而不是覆盖原有内容 |
| -i | 忽略中断信号(Ctrl+C),在长时间运行的管道任务中避免意外中断 |
使用示例
-
查看
ls -l命令输出并同时保存到文件ls -l | tee file.txt -
追加内容到日志文件
echo "this is a message" | tee -a log -
结合
sudo向需要root权限的文件写入内容echo "127.0.0.1 myapp.local" | sudo tee -a /etc/hosts执行流程:
- 不能直接使用
sudo echo "..." >> /etc/hosts,因为输出重定向>>是由当前的普通用户Shell执行的,它没有权限写入/etc/hosts - 而在这个命令中,管道
|将echo的输出传递给tee命令 tee命令是在sudo的权限提升作用下运行的,可以将从管道接收到的内容写入到/etc/hosts中
- 不能直接使用
-
将输出保存到多个文件
date | tee date_log1.txt date_log2.txt