百度360必应搜狗淘宝本站头条
当前位置:网站首页 > IT知识 > 正文

教大家简单的 Shell 脚本入门操作

liuian 2024-12-16 14:48 33 浏览

Shell脚本 运作方式与解释型语言相当,如果有语言基础,学起 Shell 脚本就非常容易,但是 Shell 与常见的语言不同,一些常见的函数在 Shell 中需要组合一些命令得以实现

工具推荐

Shell 似乎没有定制的 IDE,这里推荐 VS Code 搭配对应的插件:

  1. shellman 智能提示和自动补全,在插件页面有介绍常用代码片段的触发关键词,作者在 Shellman reborn 中写到了 Shellman 诞生的故事,挺有趣的
  2. shellcheck 语法静态检查工具,插件安装后需要本地安装 shellcheck,参考 shellcheck Installing,Mac OS 可以使用 brew install shellcheck,这样在写 Shell 的时候,语法有误的地方就会以波浪线的方式提示
  3. shell-format 代码整理,Win 快捷键:Alt + Shift + F,Mac OS 快捷键:option + shift + F
  4. Code Runner 脚本运行,右键 Run Code,Win 快捷键:Ctrl + Alt + N,Mac OS 快捷键:control + option + N

运行 shell 脚本

新建脚本:test.sh

#!/usr/bin/env bash

# 使用echo 打印字符串或者变量
echo 'hello world'

可以用 Code Runner 运行,就会输出:hello world

在 Shell脚本 的第一行一般会写 #!/bin/bash 这个是 Shebang,#! 后面是解释器的绝对路径,脚本将用该解释器执行。还有一种写法是:#!/usr/bin/env bash,/usr/bin/env 是 env 命令的绝对路径,而 env 命令用于显示系统中已存在的环境变量,其中包含了 $PATH ,会在 $PATH 包含的目录依次找 bash,常见的命令行解释器有:sh ,bash ,zsh(Mac OS 默认解释器)

如果在 Linux 或 类Unix 下运行,有这么几种方式:

  1. 先给脚本添加执行权限:chmod +x test.sh,然后运行脚本:./test.sh,这种方式执行会读取 Shebang,用指定的解释器执行脚本
  2. sh test.sh,使用 sh 这个解释器执行脚本,当然也可以用其他方式执行,比如:bash test.sh。与第一种方式相同,当前的 shell 是父进程,生成一个子 shell 进程(子进程会继承父进程的环境变量),在子 shell 中执行脚本,脚本执行完毕,退出的 shell 回到当前 shell
  3. source 点命令方式:source test.sh 等效于 . test.sh。source 让脚本在当前 shell 执行,不生成新的子进程。使用 source 执行脚本,脚本中对于环境变量的修改会作用于当前 shell,这就是为什么我们在修改了一些配置如:~/.bashrc,执行 source ~/.bashrc 后配置就生效了
  4. exec 方式:有需要先给脚本添加执行权限:chmod +x test.sh,执行 exec ./test.sh,也是让脚本在同一个进程上执行不生成新的子进程,与 source 的区别就是,在脚本执行完成后进程会被结束

基础命令

可以按照 [Bash Shell] Shell学习笔记 学习,这篇文章讲得非常详细,本篇博客也是在学习这篇文章后写下的

获取输入

使用 read 命令,从标准输入流 (stdin) 获取输入

#!/usr/bin/env bash
read var
echo "${var}"

运行脚本,输入任意字符,回车确认,输入的值会赋值给变量 var,并打印出该变量

输出

#!/usr/bin/env bash
var=1
# 输出变量
echo ${var}
# 输出字符串 显示部分字符需要转义
echo "\"hello world\"" # "hello world"

# 换行使用 -e 参数:使转义字符生效
# 使用 \n 换行
echo -e "newline\n"

也可以让 shell 输出不同颜色的字符,可以参考:shell脚本中echo显示内容带颜色

#!/usr/bin/env bash
echo -e "\033[30m 黑色字 \033[0m" 
echo -e "\033[31m 红色字 \033[0m" 
echo -e "\033[32m 绿色字 \033[0m" 
echo -e "\033[33m 黄色字 \033[0m" 
echo -e "\033[34m 蓝色字 \033[0m" 
echo -e "\033[35m 紫色字 \033[0m" 
echo -e "\033[36m 天蓝字 \033[0m" 
echo -e "\033[37m 白色字 \033[0m" 

变量使用

# = 两边不能有空格
var="hello world"
num=100


# 在引用变量时,这种方式可以,但是推荐下面一种
echo $var
# 推荐在使用字符串变量时,在两侧加上双引号,否则如果变量字符串中存在空格,则字符串会被切分
echo "$var"
# 如果涉及字符串拼接,可以在变量名两侧加上花括号
echo "变量为: ${var}."

# 将变量设置为只读,再次修改会报错
readonly var
# var="wolrd"

# 删除变量,不能删除 readonly 修饰的变量
unset num

变量赋值时,变量名命名规则和其他语言类似,注意变量赋值时 = 两边不能有空格

使用时在变量名前加上 $,推荐所有的变量都使用 ${} 的方式使用变量

运算

算术运算:Bash 原生不支持数学运算,可以使用 awk 和 expr

注意乘号需要加上转义:\*,而且运算符两侧必须空格

a=10
b=3
val=`expr $a + $b`
echo "a + b : $val"
val=`expr $a - $b`
echo "a - b : $val"
val=`expr $a \* $b`
echo "a * b : $val"
val=`expr $b / $a`
echo "b / a : $val"
val=`expr $b % $a`
echo "b % a : $val"

执行命令

$()与 ``(反引号)都可以用于执行命令,并会将执行的结果返回,shellcheck 推荐使用第一种 $() 的方式

#!/usr/bin/env bash
result=`date "+%Y-%m-%d"`
echo "${result}"

result=$(date "+%Y-%m-%d")
echo "${result}"

运算符

关系运算符只支持数字,如果字符串为数字也可以,关系运算符包括:

运算符

含义

-eq

等于

-ne

不等于

-gt

大于

-lt

小于

-ge

大等于

-le

小等于

条件表达式必须放在 [] 中,并且 [ 的右侧,和 ] 的左侧必须留有空格

布尔运算符列表:

运算符

含义

!

-o

或 (or)

-a

与 (and)

#!/usr/bin/env bash

a="10"
b="3"
c=1

if [ ${a} -ne ${b} ]
then
    echo "相同"
else
    echo "不相同"
fi

if [ ${a} -gt ${b} -a ${b} -gt ${c} ]
then
    echo "a > b & b > c"
fi

其他常用判断:

  1. 直接在 [ ] 中放字符串变量 如 [ ${str} ] 则就是判断 str 这个字符串是否非空
  2. -f 判断是否为普通文件,如:[ -f $file ]
  3. -d 判断是否为文件夹,如:[ -d $file ]

字符串截取

字符截取的格式:${string: start :length}
索引从 0 开始,可以省略 :length 这样就截取到最后,注意空格要空在 : 后,否则可能提示:bad substitution

#!/usr/bin/env bash
string="hello world"
echo ${string: 1 : 3} # ell
# 截取到最后
echo ${string:1} # ello world

数组

#!/usr/bin/env bash
# 1. 定义数组:使用括号声明,用“空格”分隔开,也可以换行隔开
arr=(1 2 3)
strArr=(
"first"
"second"
)

# 2. 读取数组:通过下标读取,下标从 0 开始计算
echo "${arr[0]}"

# 使用 * 或者 @ 读取所有元素
echo ${arr[*]}
echo ${arr[@]}

# 读取数组长度 读取全部元素前面加上 #
echo ${#arr[*]}
echo ${#arr[@]}

# 遍历下标
for(( i=0;i<${#strArr[@]};i++)) 
do
echo ${strArr[i]};
done;

# for in 遍历元素
for element in ${strArr[*]}
do
echo $element
done

# 3. 修改数组元素
strArr[0]="modify"
echo ${strArr[0]}

# 4. 删除元素
unset arr[1]
echo ${#arr[*]}
echo ${arr[*]} # 1 3
# !使用 unset 要注意,这其实并不是真正删除了该元素,而只是将该元素置空,所以使用下标遍历会出问题,如下
echo "数组遍历:"
for(( i=0;i<${#arr[@]};i++)) 
do
echo "index ${i} -> ${arr[i]}";
done;
# index 0 -> 1
# index 1 -> 

# 解决 unset 无法真正删除的方法:重新赋值给新的数组
echo "数组遍历:"
arr=( "${arr[@]}" )
for(( i=0;i<${#arr[@]};i++)) 
do
echo "index ${i} -> ${arr[i]}";
done;
# index 0 -> 1
# index 1 -> 3

判断语句

使用 if 和 fi 定义判断的边界,使用 then , elif , else 定义条件

#!/usr/bin/env bash
#!/usr/bin/env bash

a=10
b=20
if [ $a == $b ]
then
    echo "相等"
else
    echo "不相等"
fi

if [ $a == $b ]
then
    echo "相等"
elif [ $a -lt $b ]
then
    echo "a 小于 b"
else
    echo "其他情况"
fi

函数

调用函数时,我们可以传入参数,可以通过 $n 来获取参数,这里的 n 表示 需要取的参数的索引,当n>=10时,需要使用${n}来获取参数

$# 传递给函数的参数个数,$* 和 $@ 显示所有传递给函数的参数,$? 表示函数的返回值,也可以用于获取上一个命令的退出状态,执行成功会返回 0,失败返回 1

# 定义函数
#!/usr/bin/env bash
funWithParam(){
    echo "参数个数:$#"  # 参数个数:11
    echo "传递给函数的所有参数:$*" # 传递给函数的所有参数:1 2 3 4 5 6 7 8 9 34 73
    echo "$1" # 1

    # 超过 9 的参数需要用 ${} 接收参数,否则直接显示数值
    echo "$10" # 10
    echo "${11}" # 73  
}

# 调用函数:函数名后面直接跟上参数
funWithParam 1 2 3 4 5 6 7 8 9 34 73
echo "$?" # 0

输入输出重定向

使用 > 将应该输出到终端上的数据重定向输出到文件,> 默认为覆盖文件,使用 >> 追加写入文件
使用 < 将默认从键盘输入的数据,定向为从文件输入

# who 命令用于显示系统中有哪些使用者正在上面
# 将结果输入 who.txt
who > who.txt

# wc -l 作用是计算文本行数
wc -l < who.txt

一般情况下,每个 Unix/Linux 命令运行时都会打开三个文件:

  1. 标准输入 (stdin):stdin 的文件描述符为 0,Unix 程序默认从 stdin 读取数据
  2. 标准输出 (stdout):stdout 的文件描述符为 1,Unix 程序默认向 stdout 输出数据
  3. 标准错误输出 (stderr):stderr 的文件描述符为 2,Unix 程序会向 stderr 流中写入错误信息

所以一般我们后台启动应用并且输出日志文件都使用:

nohup java -jar xxx.jar >> nohup.log  2>&1 & 

nohup:(no hang up) 保证在退出帐户或者关闭终端之后继续运行相应的进程
>> nohup.log:将 java -jar xxx.jar 的输出追加到 nohup.log 文件
2>&1:将 java -jar xxx.jar 的 标准错误输出 也重定向到 标准输入
&:让进程在后台运行

默认情况下,command > file 将 stdout 重定向到 file,command < file 将stdin 重定向到 file。
如果希望 stderr 重定向到 file,可以这样写:

坑梳理

  1. 变量赋值时,变量名命名规则和其他语言类似,注意变量赋值时 = 两边不能有空格
  2. 数组 unset 元素,并不是真正的移除元素
  3. 获取参数时,当 n>=10 时,需要使用${n}来获取参数

常见的特殊 Shell 环境变量

  • $ 表示当前Shell进程的ID,即pid
  • $0 表示当前脚本的绝对路径
  • $# 传递给脚本或函数的参数个数
  • $n 传递给脚本或函数的参数
  • $? 上个命令的退出状态
  • $* 和 $@ 传递给脚本或函数的所有参数
  • $n n 代表 1~9 其中任意一个数字,传递给脚本或函数该位置的参数

$* 和 $@ 区别:

#!/usr/bin/env bash
function asterisk () {
    echo "\"\$*\""
    for var in "$*"
    do
        echo "$var"
    done
}

function mail () {
    echo "\"\$@\""
    for var in "$@"
    do
    echo "$var"
    done
}
asterisk a b c 
mail a b c

输出

"$*"
a b c
"$@"
a
b
c

当 $* 和 $@ 直接使用效果相同,都是接收一份数据如上所示的例子,接收到的就是:a b c,一份数据,以空格隔开。加了双引号后 "$@" 会将每个参数都当成一份独立的数据

原文链接:https://www.cnblogs.com/aaronlinv/p/15764053.html

相关推荐

GANs为何引爆机器学习?这篇基于TensorFlow的实例教程为你解惑!

「机器人圈导览」:生成对抗网络无疑是机器学习领域近三年来最火爆的研究领域,相关论文层出不求,各种领域的应用层出不穷。那么,GAN到底如何实践?本文编译自Medium,该文作者以一朵玫瑰花为例,详细阐...

高丽大学等机构联合发布StarGAN:可自定义表情和面部特征

原文来源:arXiv、GitHub作者:YunjeyChoi、MinjeChoi、MunyoungKim、Jung-WooHa、SungKim、JaegulChoo「雷克世界」编译:嗯~...

TensorFlow和PyTorch相继发布最新版,有何变化

原文来源:GitHub「机器人圈」编译:嗯~阿童木呀、多啦A亮Tensorflow主要特征和改进在Tensorflow库中添加封装评估量。所添加的评估量列表如下:1.深度神经网络分类器(DNNCl...

「2022 年」崔庆才 Python3 爬虫教程 - 深度学习识别滑动验证码缺口

上一节我们使用OpenCV识别了图形验证码躯壳欧。这时候就有朋友可能会说了,现在深度学习不是对图像识别很准吗?那深度学习可以用在识别滑动验证码缺口位置吗?当然也是可以的,本节我们就来了解下使用深度...

20K star!搞定 LLM 微调的开源利器

LLM(大语言模型)微调一直都是老大难问题,不仅因为微调需要大量的计算资源,而且微调的方法也很多,要去尝试每种方法的效果,需要安装大量的第三方库和依赖,甚至要接入一些框架,可能在还没开始微调就已经因为...

大模型DeepSeek本地部署后如何进行自定义调整?

1.理解模型架构a)查看深度求索官方文档或提供的源代码文件,了解模型的结构、输入输出格式以及支持的功能。模型是否为预训练权重?如果是,可以在预训练的基础上进行微调(Fine-tuning)。是否需要...

因配置不当,约5000个AI模型与数据集在公网暴露

除了可访问机器学习模型外,暴露的数据还可能包括训练数据集、超参数,甚至是用于构建模型的原始数据。前情回顾·人工智能安全动态向ChatGPT植入恶意“长期记忆”,持续窃取用户输入数据多模态大语言模型的致...

基于pytorch的深度学习人员重识别

基于pytorch的深度学习人员重识别Torchreid是一个库。基于pytorch的深度学习人员重识别。特点:支持多GPU训练支持图像的人员重识别与视频的人员重识别端到端的训练与评估简单的re...

DeepSeek本地部署:轻松训练你的AI模型

引言:为什么选择本地部署?在AI技术飞速发展的今天,越来越多的企业和个人希望将AI技术应用于实际场景中。然而,对于一些对数据隐私和计算资源有特殊需求的用户来说,云端部署可能并不是最佳选择。此时,本地部...

谷歌今天又开源了,这次是Sketch-RNN

前不久,谷歌公布了一项最新技术,可以教机器画画。今天,谷歌开源了代码。在我们研究其代码之前,首先先按要求设置Magenta环境。(https://github.com/tensorflow/magen...

Tensorflow 使用预训练模型训练的完整流程

前面已经介绍了深度学习框架Tensorflow的图像的标注和训练数据的准备工作,本文介绍一下使用预训练模型完成训练并导出训练的模型。1.选择预训练模型1.1下载预训练模型首先需要在Tensorf...

30天大模型调优学习计划(30分钟训练大模型)

30天大模型调优学习计划,结合Unsloth和Lora进行大模型微调,掌握大模型基础知识和调优方法,熟练应用。第1周:基础入门目标:了解大模型基础并熟悉Unsloth等工具的基本使用。Day1:大模...

python爬取喜马拉雅音频,json参数解析

一.抓包分析json,获取加密方式1.抓包获取音频界面f12打开抓包工具,播放一个(非vip)视频,点击“媒体”单击打开可以复制URL,发现就是我们要的音频。复制“CKwRIJEEXn-cABa0Tg...

五、JSONPath使用(Python)(json数据python)

1.安装方法pipinstalljsonpath2.jsonpath与Xpath下面表格是jsonpath语法与Xpath的完整概述和比较。Xpathjsonpath概述/$根节点.@当前节点...

Python网络爬虫的时候json=就是让你少写个json.dumps()

大家好,我是皮皮。一、前言前几天在Python白银交流群【空翼】问了一个Python网络爬虫的问题,提问截图如下:登录请求地址是这个:二、实现过程这里【甯同学】给了一个提示,如下所示:估计很多小伙伴和...