9 个 Bash 脚本示例让您开始使用 Linux
已发表: 2022-07-05如果您刚开始在 Linux 上编写 Bash 脚本,那么扎实掌握基础知识将对您有利。 它们是更深入的知识和更高的脚本技能的基础。
记住,让你的脚本可执行
要让 shell 执行脚本,脚本必须具有可执行文件权限集。 没有这个,你的脚本只是一个文本文件。 有了它,它仍然是一个文本文件,但 shell 知道它包含指令,并会在脚本启动时尝试执行它们。
编写脚本的全部意义在于它们可以运行,所以第一步是要知道如何让 Linux 知道你的脚本应该被认为是可执行的。
chmod
命令让我们设置文件权限。 可以使用 +x 标志设置执行权限。
chmod +x script1.sh
您需要对每个脚本执行此操作。 将“script1.sh”替换为您的脚本名称。
1. 奇怪的第一行是什么?
脚本的第一行告诉 shell 应该调用哪个解释器来运行该脚本。 第一行必须以 shebang 开头,“#!”,也称为 hashbang。 这 ”#!” 告诉 shell 这一行包含脚本所针对的解释器的路径和名称。
这很重要,因为如果您编写了要在 Bash 中运行的脚本,您不希望它被不同的 shell 解释。 可能存在不兼容的情况。 与大多数 shell 一样,Bash 有自己的语法和功能,而其他 shell 没有,或者以不同的方式实现。
当您运行脚本时,当前 shell 打开脚本并确定应该使用哪个 shell 或解释器来执行该脚本。 然后它启动那个 shell 并将脚本传递给它。
#!/bin/bash echo 在 $SHELL 中运行
该脚本的第一行可以读作“使用位于 /bin/bash 的解释器来运行此脚本”。
脚本中唯一的一行将$SHELL
环境变量中保存的值写入终端屏幕。 这证实了使用 Bash 执行脚本。
./script1.sh
作为一个小技巧,我们可以证明脚本被传递给我们选择的任何解释器。
#!/bin/cat 所有文本行都传递给 cat 命令 并打印在终端窗口中。 那包含着 舍邦线。
脚本2.sh
此脚本由当前 shell 启动并传递给cat
命令。 cat
命令“运行”脚本。
像这样编写你的 shebangs 假设你知道 shell 或其他解释器在目标机器上的位置。 99% 的情况下,这都很好。 但是有些人喜欢对冲他们的赌注并像这样写他们的shebangs:
#!/usr/bin/env bash echo 在 $SHELL 中运行
脚本3.sh
当脚本启动时,shell 会搜索命名 shell 的位置。 如果 shell 恰好位于非标准位置,这种方法可以避免“错误解释器”错误。
别听,他在说谎!
在 Linux 中,总是有不止一种方法可以给猫剥皮或证明作者的错误。 完全符合事实的是,有一种方法可以在没有 shebang 的情况下运行脚本,并且不让它们可执行。
如果您启动要执行脚本的 shell 并将脚本作为命令行参数传递,则 shell 将启动并运行脚本——无论它是否可执行。 因为您在命令行上选择了 shell,所以不需要 shebang。
这是整个脚本:
echo "我被处决了" $SHELL
我们将使用ls
来查看该脚本确实不可执行,并使用该脚本的名称启动 Bash:
ls
bash script4.sh
还有一种方法可以让当前shell 运行脚本,而不是专门为执行脚本而启动的 shell。 如果使用source
命令,可以缩写为单个句点“ .
“,您的脚本由您当前的 shell 执行。
因此,要在没有 shebang、没有可执行文件权限且不启动另一个 shell 的情况下运行脚本,您可以使用以下任一命令:
源脚本4.sh
. 脚本4.sh
尽管这是可能的,但不建议将其作为一般解决方案。 有缺点。
如果脚本不包含 shebang,则您无法判断它是为哪个 shell 编写的。 一年后你会记得吗? 如果脚本没有设置可执行权限, ls
命令不会将其识别为可执行文件,也不会使用颜色将脚本与纯文本文件区分开来。
相关:命令行:为什么人们仍然为它们烦恼?
2. 打印文本
向终端写入文本是一项常见要求。 一点视觉反馈会有很长的路要走。
对于简单的消息, echo
命令就足够了。 它允许对文本进行一些格式化,也允许您使用变量。
#!/bin/bash echo 这是一个简单的字符串。 echo "这是一个包含'单引号'的字符串,所以它用双引号括起来。" echo "这将打印用户名:" $USER echo -e "-e 选项让我们使用\n格式化指令\n分割字符串。"
./script5.sh
printf
命令为我们提供了更大的灵活性和更好的格式化功能,包括数字转换。
此脚本使用三个不同的数字基数打印相同的数字。 十六进制版本也被格式化为以大写形式打印,前导零和三位数的宽度。
#!/bin/bash printf "十进制:%d,八进制:%o,十六进制:%03X\n" 32 32 32
./script6.sh
请注意,与echo
不同,您必须告诉printf
以“ \n
”标记开始新行。
3. 创建和使用变量
变量允许您在程序中存储值并操作和使用它们。 您可以创建自己的变量或使用环境变量作为系统值。
#!/bin/bash millennium_text="千禧年以来的岁月:" current_time=$(日期'+%H:%M:%S') todays_date=$( 日期 '+%F' ) 年=$(日期'+%Y') echo "当前时间:" $current_time echo "今天的日期:" $todays_date years_since_Y2K=$(( 年 - 2000 )) 回声 $millennium_text $years_since_Y2K
此脚本创建一个名为millennium_text
的字符串变量。 它包含一行文本。
然后它创建三个数值变量。
-
current_time
变量被初始化为脚本执行的时间。 -
todays_date
变量设置为脚本运行的日期。 -
year
变量保存当前年份。
要访问存储在变量中的值,请在其名称前加上美元符号“$”。
./script7.sh
该脚本打印时间和日期,然后计算自千禧年以来已经过去了多少年,并将其存储在years_since_Y2K
变量中。
最后,它打印包含在millennium_text
变量中的字符串和存储在years_since_Y2K
中的数值。
相关:如何在 Bash 中使用变量
4. 处理用户输入
要允许用户输入脚本将使用的值,您需要能够捕获用户的键盘输入。 Bash read
命令允许 ut 做到这一点。 这是一个简单的例子。
#!/bin/bash echo "输入一个数字并点击\"Enter\"" 读取用户编号 1; echo "输入另一个数字并点击 \"Enter\"" 读取用户编号2; printf "你输入了:%d 和 %d\n" $user_number1 $user_number2 printf "把它们加在一起:%d\n" $((user_number1 + user_number2))
该脚本提示输入两个数字。 它们从键盘读取并存储在两个变量user_number1
和user_number2
中。
该脚本将数字打印到终端窗口,将它们加在一起,然后打印总数。
./script8.sh
我们可以使用-p
(提示)选项将提示组合到read
命令中。
#!/bin/bash read -p "输入一个数字并点击\"Enter\" " user_number1; read -p "输入另一个数字并点击\"Enter\" " user_number2; printf "你输入了:%d 和 %d\n" $user_number1 $user_number2 printf "把它们加在一起:%d\n" $((user_number1 + user_number2))
这使事情更整洁,更容易阅读。 易于阅读的脚本也更易于调试。
./script9.sh
该脚本现在的行为略有不同。 用户输入与提示位于同一行。
要捕获键盘输入而不将其回显到终端窗口,请使用-s
(静默)选项。
#!/bin/bash read -s -p "输入您的密码并点击 \"Enter\" " secret_PIN; printf "\nShhh ... 它是 %d\n" $secret_PIN
./script10.sh
输入值被捕获并存储在一个名为secret_PIN
的变量中,但是当用户键入它时它不会回显到屏幕上。 之后你用它做什么取决于你。
5.接受参数
有时接受用户输入作为命令行参数比让脚本等待输入更方便。 将值传递给脚本很容易。 它们可以在脚本中被引用,就像它们是任何其他变量一样。
第一个参数变为变量$1
,第二个参数变为变量$2
,依此类推。 变量$0
始终保存脚本的名称,变量$#
保存命令行中提供的参数数量。 变量$@
是一个包含所有命令行参数的字符串。
#!/bin/bash printf "这个脚本被调用:%s\n" $0 printf "你使用了 %d 个命令行参数\n" $# # 循环遍历变量 对于“$@”中的参数; 做 回声“$参数” 完毕 echo "参数 2 是:" $2
该脚本使用$0
和$#
来打印一些信息。 然后使用?@
循环所有命令行参数。 它使用$2
来展示如何访问单个特定的参数值。
./script11.sh
将几个单词用引号“””括起来,将它们组合成一个参数。
6. 从文件中读取数据
知道如何从文件中读取数据是一项很棒的技能。 我们可以在 Bash 中使用 while 循环来做到这一点。
#!/bin/bash 行数=0 而 IFS='' 读取 -r LinefromFile || [[ -n "${LinefromFile}" ]]; 做 ((线数++)) echo "读取行 $LineCount: ${LinefromFile}" 完成 <"$1"
我们将希望脚本处理的文件的名称作为命令行参数传递。 这将是唯一的参数,因此在脚本中$1
将保存文件名。 我们将该文件重定向到while
循环中。
while
循环使用IFS=''
赋值将内部字段分隔符设置为空字符串。 这可以防止read
命令在空白处拆分行。 只有行尾的回车才被认为是真正的行尾。
[[ -n "${LinefromFile}" ]]
子句满足文件中最后一行不以回车符结尾的可能性。 即使没有,最后一行也将被正确处理并被视为常规的 POSIX 兼容行。
./script12.sh 闪烁.txt
7. 使用条件测试
如果您希望脚本针对不同的条件执行不同的操作,则需要执行条件测试。 双括号测试语法起初提供了大量的选项。
#!/bin/bash 价格=$1 如果 [[ 价格 -ge 15 ]]; 然后 回声“太贵了。” 别的 回声“买!” 菲
Bash 提供了一整套比较运算符,可让您确定诸如文件是否存在、是否可以读取文件、是否可以写入文件以及目录是否存在等内容。
它还对等于-qe
、大于-gt
、小于或等于-le
等进行了数值测试,尽管您也可以使用熟悉的==
、 >=
、 <=
表示法。
./script13.sh 13
./script13.sh 14
./script13.sh 15
./script13.sh 16
8. for 循环的威力
一遍又一遍地重复动作最好使用循环来完成。 for
循环允许您多次运行循环。 这可能达到一个特定的数字,或者可能直到循环通过项目列表。
#!/bin/bash 对于 (( i=0; i<=$1; i++ )) 做 echo "C 风格的 for 循环:" $i 完毕 对于我在 {1..4} 做 echo "For 循环范围:" $i 完毕 对于 i 在 "零" "一" "二" "三" 做 echo "带有单词列表的 For 循环:" $i 完毕 网站="如何极客" 对于我在 $website 做 echo "带有单词集合的 For 循环:" $i 完毕
所有这些循环都是for
循环,但它们使用不同类型的循环语句和数据。
./script14.sh 3
第一个循环是经典的 C 风格for
循环。 循环计数器i
初始化为零,并随着循环的每个循环递增。 当i
的值小于或等于$1
中保存的值时,循环将继续运行。
第二个循环处理从 1 到 4 的数字范围。第三个循环处理一个单词列表。 虽然有更多的词要处理,但循环会不断重复。
最后一个循环遍历字符串变量中的单词列表。
9. 功能
函数允许您将代码段封装到命名例程中,这些例程可以从脚本中的任何位置调用。
假设我们希望从文件中读取行的脚本对每一行进行某种处理。 将该代码包含在函数中会很方便。
#!/bin/bash 行数=0 函数 count_words() { printf "%d 行中的 %d 个单词\n" $(echo $1 | wc -w) $2 } 而 IFS='' 读取 -r LinefromFile || [[ -n "${LinefromFile}" ]]; 做 ((线数++)) count_words "$LinefromFile" $LineCount 完成 <"$1" count_words "这不在循环中" 99
我们通过添加一个名为count_words
的函数来修改我们的文件读取程序。 它是在我们需要使用它之前定义的。
函数定义以单词function
开头。 接下来是我们函数的唯一名称,后跟括号“ ()
”。 函数的主体包含在大括号“{}”中。
函数定义不会导致任何代码被执行。 在调用函数之前,函数中的任何内容都不会运行。
count_words
函数打印一行文本中的单词数和行号。 这两个参数被传递到函数中,就像参数被传递到脚本中一样。 第一个参数成为函数变量$1
,第二个参数成为函数变量$2
,依此类推。
while
循环从文件中读取每一行并将其与行号一起传递给count_words
函数。 为了表明我们可以从脚本中的不同位置调用该函数,我们在while
循环之外再次调用它。
./script15.sh 闪烁.txt
不要害怕学习曲线
脚本是有益的和有用的,但很难进入。 一旦掌握了一些可重用的技术,您将能够相对轻松地编写有价值的脚本。 然后您可以查看更高级的功能。
在跑步之前先步行,并花时间享受旅程。
相关: 10 个适合初学者的基本 Linux 命令