新闻详情

新闻详情

首页 / 资讯中心 / 详情

Linux Shell脚本入门:从创建到运行,Bash实战详解

发布时间:2026/9/30 1:17:05来源:尧图网络
Linux Shell脚本入门:从创建到运行,Bash实战详解
先问个问题你第一次打开 Linux 终端是不是对着黑乎乎的窗口发呆然后默默关掉心想“这玩意儿到底能干嘛”我当年的反应一模一样。直到后来我明白了一个事实——终端不是一个“窗口”而是一个“对话入口”。你每敲一条命令都是在和操作系统说一句话。而 Shell 脚本就是把这一串对话提前写好让系统一次性执行完。这篇文章要讲的就是 Bash 初学者最需要掌握的一条完整路径创建脚本、写内容、给权限、运行它。我会把每个步骤背后的“为什么”也讲清楚而不是只丢给你几条命令。毕竟 Linux 下最不缺的就是命令缺的是理解。这篇内容适合完全零基础的新手也适合那些已经会敲 ls、cd但从来没正经写过脚本的人。看完你会知道脚本到底长什么样、为什么第一行是那串奇怪的符号、chmod 755 是什么鬼、为什么运行要加 ./以及遇到最常见的那几个报错该怎么处理。1. 先搞清楚Shell、Bash、脚本这三者到底是什么关系新手容易绕晕的第一个点就是 Shell、Bash、脚本这三个词的交错出现。我会把这三者的关系简化成一句话Shell 是 Linux 系统的“翻译官”Bash 是翻译官中最常见的一位而脚本就是给这位翻译官的“提词稿”。1.1 Shell 是用户和内核之间的翻译层Linux 系统真正干活的叫“内核”也就是 Kernel。但内核听不懂人话你也不可能直接跟它交流。中间就需要一层“壳”也就是 Shell来接收你的输入、翻译成内核能理解的指令、再把执行结果反馈给你。你可以这样理解你去一家外国餐厅吃饭服务员负责把你想吃的菜转达给后厨。这个服务员就是 Shell。你换一个服务员点菜的方式可能略有不同但最终后厨做的还是那道菜。常见的 Shell 有 Bash、Zsh、Fish、Sh 等它们都是“服务员”只是服务风格略有差异。这个类比里最重要的启发是Shell 本身是一个程序不是系统底层的东西。Linux 默认安装了 Bash你开机看到的那个终端界面本质上就是 Bash 这个程序在运行。1.2 Bash 为什么能成为默认 ShellBashBourne Again Shell是 Steve Bourne 写的 Bourne Shellsh的增强版本。它兼容了 sh 的语法又加入了很多便利功能比如命令历史、别名、数组、算术运算等。多年下来它成了几乎所有 Linux 发行版默认安装和默认使用的 Shell。你可以用这条命令查看当前系统用的什么 Shellecho $SHELL输出一般是/bin/bash或者/usr/bin/bash这就说明你的默认 Shell 是 Bash。另外要明白一个容易混淆的概念sh、bash、zsh是不同的程序。虽然很多脚本开头写的是#!/bin/sh但在绝大多数 Linux 系统上/bin/sh其实是一个指向bash的符号链接只是运行时会进入“POSIX 兼容模式”。所以初学者不必过度纠结这两者的差异写脚本时统一用#!/bin/bash就好。1.3 脚本的本质就是“批处理命令”脚本不是一个特殊的文件格式它就是一个普通的文本文件里面一行一行写着待执行的命令。Bash 会从上到下逐行读取、逐行执行。这就像你写了一个“今日待办清单”打开浏览器查邮件写日报提交代码脚本也一样只不过清单里的每一项换成了 Linux 命令。手动执行和脚本执行的区别在于手动是你在终端里一条一条敲脚本是一次性交给系统自动完成。所以“Shell 脚本”更准确的称呼其实是“Shell 命令的集合”只是我们习惯上叫“脚本”而已。明白这一点你就不会觉得它有多高深了——你本来就会敲命令现在只是把命令写进文件让它批量跑。2. 环境准备确认你的系统里有 Bash写脚本之前先确认工作环境没问题。这一步听起来简单但我在教学过程中确实遇到过有人卡在这儿——他们用的是 Windows以为自己在“写 Linux 脚本”。2.1 先确认你用的是不是 Linux 环境Bash 脚本是给 Linux/Unix 类系统用的所以你得先有一个能运行 Bash 的环境。常见的选择有本机安装了完整的 Linux 发行版Ubuntu、CentOS、Debian、Kali 等虚拟机里装了 Linux云服务器上的 Linux 环境Windows 上通过 WSLWindows Subsystem for Linux运行 LinuxWindows 上的 Git Bash提供有限的 Bash 环境判断标准很简单打开终端能执行ls、pwd这些命令就说明你的环境是可用的。注意在 Windows 的 Git Bash 里部分行为和完整 Linux 环境有差异比如路径写法、磁盘挂载方式等。如果你是想正经学 Linux建议直接装一个虚拟机或者用云服务器别拿 Git Bash 将就。2.2 确认 Bash 版本与可用性在终端里执行bash --version正常会输出类似这样GNU bash, version 5.1.16(1)-release (x86_64-pc-linux-gnu)看到这个你的环境就没有问题。2.3 准备一个专门放脚本的目录强烈建议不要随便把脚本写到系统目录里。我自己习惯建一个~/scripts目录专门放脚本mkdir -p ~/scripts cd ~/scripts这样做的好处是脚本集中管理好备份也好找。等以后脚本多了你就知道这个习惯多重要了。3. 手把手创建你的第一个 Bash 脚本进入正题。我会带你走完整个流程创建文件、写入内容、加执行权限、运行脚本。每一步都会解释为什么这么做而不是只让你复制粘贴。3.1 用 touch 创建文件还是直接用编辑器创建脚本文件有两种常见方式方式一先创建再编辑touch hello.sh然后使用文本编辑器打开编辑vim hello.sh方式二直接用编辑器新建vim hello.sh我个人推荐直接方式二少敲一条命令。如果你不熟悉 vim 的操作可以先使用 nano它更友好nano hello.sh进入编辑器后写下如下内容#!/bin/bash echo Hello, World!然后保存退出。nano 的保存快捷键是CtrlO回车确认再CtrlX退出。vim 则是按Esc输入:wq回车。3.2 第一行#!/bin/bash的作用是什么这一行叫Shebang也称为释伴行。它看起来像注释但它绝不是普通注释。它的作用是告诉系统执行这个脚本时要用哪个解释器来解读后面的内容。一个很形象的比喻你写了一份英文报告首页写着“请让英语翻译来阅读”——Shebang 就是这个说明。Linux 内核在执行脚本时会先看第一行发现是#!/bin/bash就会调用/bin/bash这个程序来执行后续内容如果是#!/bin/python3就会调用 Python 解释器。用which bash查看你系统上 Bash 的绝对路径$ which bash /usr/bin/bash如果你不确定路径可以在脚本里写#!/usr/bin/env bash这种写法会让系统在环境变量里自动找到 bash兼容性更好。我个人的习惯是直接写#!/bin/bash因为 Linux 上这个路径几乎固定。但如果你的脚本打算在 macOS 或者各种不同的发行版之间传播#!/usr/bin/env bash会更可靠。3.3 给脚本加执行权限chmod 到底做了什么写完脚本后如果你直接运行大概率会收到Permission denied。这是因为 Linux 系统的安全模型要求“文件要有执行权限才能被当作程序运行”。查看文件权限ls -l hello.sh输出类似-rw-r--r-- 1 user user 31 Jan 1 12:00 hello.sh最前面的-rw-r--r--表示文件权限。第一个r代表可读第二个w代表可写但没有任何x也就是不可执行。给它加上执行权限chmod x hello.sh再看一次-rwxr-xr-x 1 user user 31 Jan 1 12:00 hello.sh出现了 3 个x分别代表文件所有者、所属组、其他用户都可以执行。注意chmod x给所有人加了执行权限对于自己私人的脚本没有安全问题。但如果你在意最小权限原则也可以只给文件所有者加执行权限chmod ux hello.sh。3.4 为什么运行脚本要加./不能直接写文件名这是新手问得最多的一个问题。运行方式如下./hello.sh会有这样的输出Hello, World!如果你直接输入hello.sh系统会提示bash: hello.sh: command not found原因在于Linux 在寻找可执行程序时只会在PATH环境变量指定的目录里找。当前目录.默认并不在PATH里。./的意思是明确告诉系统“就在当前目录下找这个文件”。这个设计其实是为了安全——避免一个恶意程序伪装成普通命令放在当前目录诱导你误执行。另外还有两种运行脚本的方式bash hello.sh sh hello.sh用这种方式不需要文件有执行权限因为你是直接调用 Bash 来解释执行文件里的内容。这和不加./报错的原理不同它是把脚本当作 Bash 的一个参数。3.5 路径的讲究相对路径与绝对路径运行脚本时用./hello.sh是相对路径表示“相对于当前目录的位置”。你也可以用绝对路径运行/home/你的用户名/scripts/hello.sh完全没问题。相对路径的好处是简短、不用关心脚本放在哪里绝对路径的好处是无论你在哪个目录下都能运行。如果你希望某个脚本能在任何地方直接运行可以把它放到/usr/local/bin目录或者把~/scripts加入PATH。这一步不急于现在做等你的脚本多了再研究也不迟。4. 脚本的基本语法从变量、条件到循环会创建和运行脚本之后下一步就是真正“写点有用的东西”。这一节不铺开讲所有语法而是把新手写脚本时最高频用到的语法拎出来各配一个简单例子。这几块学会了你已经能写 80% 的日常脚本了。4.1 变量与输入让脚本不再是死的一个永远输出Hello, World!的脚本没太大意义。真正有用的脚本会读取用户输入或接收参数。使用命令行参数#!/bin/bash echo 第一个参数: $1 echo 第二个参数: $2 echo 所有参数: $ echo 参数个数: $#保存后运行./args.sh hello world输出第一个参数: hello 第二个参数: world 所有参数: hello world 参数个数: 2$1、$2是位置参数$表示所有参数$#表示参数个数。这些特殊变量在脚本里非常常用。使用 read 读取用户输入#!/bin/bash echo -n 请输入你的名字: read name echo 你好, $name!read命令会让脚本暂停等待用户在键盘输入然后存到变量里。echo -n的意思是输出后不换行这样光标会停留在同一行界面更自然。4.2 条件判断让脚本能做决定shell 脚本经常会遇到“如果……就……”的场景比如检查文件是否存在、比较数字大小等。#!/bin/bash if [ -f /etc/passwd ]; then echo 文件 /etc/passwd 存在 else echo 文件不存在 fi语法要点说明if以fi结束就是把 if 反过来写这是 shell 的传统[ -f 文件 ]是“判断文件是否存在”的写法注意方括号两边必须留空格[实际上是一个命令不是语法符号这也是为什么[和]两侧都必须有空格的原因条件判断后面要加; then或者把then换行写常见的判断写法可以参考这张表写法含义[ -f 文件 ]判断文件是否存在[ -d 目录 ]判断目录是否存在[ -z 字符串 ]判断字符串是否为空[ $a $b ]判断两个字符串是否相等[ $a -gt $b ]判断 a 是否大于 b数字[ $a -lt $b ]判断 a 是否小于 b数字特别注意字符串比较用数字比较用-eq或-gt。初学者经常搞混这一点导致脚本判断结果完全不对。变量比较时强烈建议加上双引号。比如[ $name admin ]如果$name是空字符串不加引号时这一行就变成了[ admin ]语法直接报错。加引号是最稳妥的做法。4.3 for 循环批量处理的高效姿势场景你想对一批文件做同样的操作。比如在txt_files目录下有 100 个.txt文件你想在每个文件末尾加一行“EOF”。#!/bin/bash for file in /home/user/txt_files/*.txt; do echo EOF $file echo 处理完成: $file donefor … in …的结构含义是“对于这个列表中的每一项执行一次循环体”。列表可以是文件通配符、数字序列、或者是命令的结果。另一个常见写法是 C 风格的循环#!/bin/bash for i in $(seq 1 10); do echo 第 $i 次循环 done这里的$(seq 1 10)会先执行seq命令生成一到十的数字序列。$()是命令替换的写法意思是“先执行括号里面的命令把输出结果放到这里”。4.4 while 循环适合读取文件内容for 循环适合处理“已知数量”的迭代而 while 循环更适合“知道条件才停止”或“逐行读取文件”的场景。#!/bin/bash count1 while [ $count -le 5 ]; do echo count $count count$((count 1)) done这里有一个新手容易忽略的地方count$((count 1))里的$(( ))表示“做算术运算”。Shell 中的变量本质上都是字符串直接写countcount1是错误的必须用$(( ))告诉 shell 这是数学运算。另一种常见用法是逐行读取文件#!/bin/bash while read line; do echo 本行内容: $line done /etc/hostname是输入重定向意思是“把文件内容作为这个循环的输入流”。4.5 函数把重复逻辑封装起来脚本稍微长了以后总会发现有些代码块反复出现。这时候就该用函数了。#!/bin/bash log_info() { echo [INFO] $(date %Y-%m-%d %H:%M:%S) - $1 } log_error() { echo [ERROR] $(date %Y-%m-%d %H:%M:%S) - $1 2 } log_info 脚本开始执行 log_error 发生了一个错误函数定义的格式很简单函数名() { … }调用时直接写函数名。$1在函数内部代表“传给这个函数的第一参数”而不是脚本的第一参数。2表示把输出重定向到标准错误输出stderr。这样做的意义是当脚本输出被重定向到日志文件时错误信息和正常信息可以分开处理。$(date %Y-%m-%d %H:%M:%S)会先执行 date 命令得到当前时间然后嵌入到字符串里。这是脚本中最常用的“日志加时间戳”模式。5. 跑起来之后调试技巧与常见的报错处理写脚本最耗时的从来不是写而是改。新手遇到报错时第一反应往往是慌其实只要掌握系统的排查思路绝大多数问题都能在几分钟内定位。5.1 开启调试模式bash -x 是你的放大镜当你不知道脚本为什么会出错时用调试模式跑一遍bash -x script.sh输出会多出很多带号的行这些是系统在执行每一行命令前打印的“展开后的实际内容”相当于把脚本执行过程慢放给你看。比如脚本里有nameAlice echo 你好, $name使用bash -x运行时你会看到 nameAlice echo 你好, Alice 你好, Alice你就能直观地看到变量名是否被正确替换、命令是否真的执行了、引号是否导致参数被错误合并。调试完记得把-x去掉不然正常执行时也会打印这些过程信息。5.2/bin/bash^M: bad interpreter的经典坑这个报错十有八九来自 Windows 编辑器。现象是这样的bash: ./hello.sh: /bin/bash^M: bad interpreter: No such file or directory原因是 Windows 保存文件时行尾用的是\r\n回车加换行而 Linux 只认\n换行。多了的\r被系统当成文件名的一部分它去找/bin/bash^M这个解释器自然找不到。新手最容易踩这个坑的场景是用记事本写脚本再通过 U 盘或网盘传到 Linux 上运行。两个解决办法方案一在 Linux 上转换行格式sed -i s/\r$// hello.sh方案二用正确的工具编辑在 Windows 上用 Visual Studio Code 编辑文件时注意右下角设置换行符格式为 LF 而不是 CRLF或者干脆直接在 Linux 上使用 vim 编辑。5.3command not found的三种可能原因遇到command not found别急着觉得系统坏了。排查顺序如下第一种情况是命令真的不存在。确认方式which 命令名若没有输出说明系统里没装这个命令。第二种情况是脚本运行方式不对。前面提到过直接输入脚本名而不用./前缀系统找不到。这是新手最常犯的错误。第三种情况是你的PATH环境变量出了问题。比如某些软件安装后它的可执行文件目录没有加进PATH。热搜词里有个典型例子-bash: crontab: command not found很多时候是因为crontab所在目录不在当前用户的PATH中多数发行版的crontab位于/usr/bin/crontab完整路径还是能执行的。解决方法是使用绝对路径或者把目录加进PATH。5.4 权限问题和换行问题之外的隐蔽错误除了上面两种常见问题新手还容易踩这些坑中英文标点混用写脚本时括号、引号、冒号必须是英文半角如果你在中文输入法状态下写一个中文引号能让你排查半小时。$忘记加引用变量时要写$变量名但赋值时写变量名值即可。有人习惯性地在赋值时也加$就会报错。空格问题a 1会报错正确的是a1但[ $a 1 ]这条命令式的写法又必须留空格。规则不一样容易弄混。命令替换写成单引号$(date)会执行 date 命令但$(date)只是字面字符串单引号会阻止所有展开行为。5.5 让脚本“用起来安全”的几条建议作为从新手走过来的人我特别想分享几条关于脚本安全的经验关键操作前加检查比如删除文件前先echo出要删除的文件名确认无误再真正执行。给脚本加set -e放在脚本第二行表示“只要任何一条命令出错就立即退出”避免错误被连带执行下去。考虑加set -u使用未定义的变量时直接报错这能避免变量名拼写错误导致的隐性 bug。#!/bin/bash set -euo pipefail echo 开始执行脚本set -euo pipefail是很多生产环境脚本都会加的一行初学者可能不完全理解每一段含义但是先养成加上的习惯能少踩很多坑。6. 综合实战写一个日志备份脚本基础语法讲完了我带你从头到尾写一个真正有点用的小脚本把指定目录下超过 7 天的日志文件压缩归档并清理原始文件整个过程输出日志。这个例子综合了变量、条件、循环、时间运算、函数等前面所有知识点你可以照抄后改成自己的需求。6.1 需求分析与脚本设计需求拆解如下指定一个日志目录找到目录下后缀是.log的文件对超过 7 天的文件进行压缩归档压缩成功后删除原始文件打印操作日志写成脚本后结构如下#!/bin/bash set -euo pipefail LOG_DIR/var/log/myapp BACKUP_DIR/var/log/myapp/archive KEEP_DAYS7 mkdir -p $BACKUP_DIR archive_log() { local file$1 local filename filename$(basename $file) local target$BACKUP_DIR/${filename}.$(date %Y%m%d).tar.gz echo 正在压缩: $file tar -czf $target $file if [ $? -eq 0 ]; then echo 压缩成功删除原文件: $file rm $file else echo 压缩失败保留原文件: $file fi } export -f archive_log find $LOG_DIR -maxdepth 1 -name *.log -type f -mtime $KEEP_DAYS -exec bash -c archive_log $ _ {} \; echo 备份任务完成6.2 逐段解析为什么这样写这一段脚本建议你自己手动敲一遍感受一下每个部分存在的意义set -euo pipefail一开始就定义了“出错就退出”的原则。LOG_DIR等变量集中定义在头部方便修改也保持脚本整洁。archive_log函数里的local file$1函数的局部变量不会污染全局命名空间。filename$(basename $file)从完整路径中提取文件名。tar -czfc 表示创建归档z 表示用 gzip 压缩f 指定文件名这是最常用的打包压缩组合。if [ $? -eq 0 ]$?是上一条命令的返回值0 表示成功非 0 表示失败。find ... -exec bash -c ...对每个符合条件的文件执行一次命令。这里用了-mtime 7来匹配修改时间超过 7 天的文件。{} 和 \;find找到的每个文件名会替换进{}\;表示命令结束。6.3 测试脚本的正确姿势写完之后不要直接在真实目录上跑先在测试目录模拟mkdir -p /tmp/test_log cd /tmp/test_log for i in $(seq 1 10); do echo 日志内容 $i access_$i.log done然后批量改时间让文件“变老”touch -d 10 days ago /tmp/test_log/*.log接着把脚本里的LOG_DIR改成/tmp/test_logBACKUP_DIR改成/tmp/test_log/archive用bash -x跑一遍仔细看输出过程是否符合预期。确认没问题后再部署到真实环境。这个“先测试后生产”的习惯是脚本写作中特别重要的一环。一些个人体会写脚本这件事入门门槛其实非常低你今天学会的已经够用了。但要想真正提升我的经验是别背语法去写脚本。你写一个自动备份目录的脚本、写一个批量改文件名的脚本、写一个定时清理临时文件的脚本每一个真实需求都会逼你去查语法、踩坑、调试这一轮下来比你看十篇教程都有效。另外想提醒一点脚本里能用中文注释就尽量写清楚。我自己早期写的脚本为了省事没有注释三个月后回来看完全不知道那段逻辑在干嘛。加注释不是给别人看的是给未来的自己看的。最后分享我的一个小习惯——每次写完脚本我会刻意问自己两个问题如果这个目录不存在脚本会怎样如果输入的文件名里带了空格脚本会怎样把这两个问题想明白并处理掉你的脚本就已经超过了大多数初学者。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

KeyarchOS上部署Ktransformers:AMX指令集加速CPU大模型推理 2026/9/30 3:00:13

KeyarchOS上部署Ktransformers:AMX指令集加速CPU大模型推理

自从开始折腾本地大模型,我就一直在跟显存较劲。我手里那张消费级显卡,6GB显存,跑7B小模型勉强能看,可一碰到70B级别的大模型,连权重都装不下,更别提推理了。当时圈子里流行的方案是纯CPU推理,内…

阅读更多 →
PyTorch torch.nn 底层逻辑:Parameter、Module 与梯度管理 2026/9/30 3:00:13

PyTorch torch.nn 底层逻辑:Parameter、Module 与梯度管理

第一次用 PyTorch 跑通神经网络的人,大概率都有过这样的经历:对着 nn.Sequential 抄了一段 LeNet,model(x) 输出 10 维 logits,loss.backward() 一把梭,准确率还不错。代码确实能跑,但 torch.nn 究竟做了什…

阅读更多 →
Elasticsearch Serverless无状态架构:计算存储分离解决集群扩缩容难题 2026/9/30 3:00:06

Elasticsearch Serverless无状态架构:计算存储分离解决集群扩缩容难题

手头有个搜索和日志分析的场景,数据量说大不大说小不小,但业务波动特别明显——白天高峰和夜间低谷能差几十倍。用传统 Elasticsearch 集群扛这种流量,要么常年空转浪费资源,要么扩容速度跟不上突发流量。后来我把项目迁到了 Elas…

阅读更多 →
软考初级程序员第一章PPT:计算机系统基础知识考点拆解与自测 2026/9/30 3:00:06

软考初级程序员第一章PPT:计算机系统基础知识考点拆解与自测

简介:这份PPT面向备考软考初级程序员的考生,聚焦第一章计算机系统基础知识,帮助考生在有限时间内系统梳理高频考点。资源为单个pptx文件,压缩包约6.92MB,内容紧贴考试大纲,重点突出、总结到位。课件依次覆盖…

阅读更多 →
Kylin系统离线安装g++:依赖处理与本地源搭建实战 2026/9/30 3:00:06

Kylin系统离线安装g++:依赖处理与本地源搭建实战

刚拿到一台Kylin初始系统的服务器,网络是隔离的内网,连yum仓库都连不出去,第一个任务就是离线配置g。这事儿听起来像一条命令的事,但真正在离线环境里做过的都知道,光是“离线”两个字就能把人折腾够呛。我这次把整个过…

阅读更多 →
WPE封包外挂教程:截包分析、滤镜制作与独立外挂打包 2026/9/30 3:00:06

WPE封包外挂教程:截包分析、滤镜制作与独立外挂打包

简介:面向游戏封包分析与外挂制作初学者的WPE系统教程,以六十五页内容详实的Word文档,完整梳理WPE各版本下载安装、封包截取原理、S包查找思路,以及滤镜制作与独立外挂生成流程。教程从选择client.exe进程、发送特定消息并截包等基…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉