首页 > 系统相关 >POSIX-shell学习笔记

POSIX-shell学习笔记

时间:2024-07-30 23:50:17浏览次数:12  
标签:Command shell 笔记 echo sh exit trap https POSIX

学习POSIX shell建议使用dash,因为它很快:https://unix.stackexchange.com/a/148098

man dash: Only features designated by POSIX, plus a few Berkeley extensions, are being incorporated into this shell.

条件判断

man dash,然后搜索test expression,可以看到完整的列表。

if elif else

#!/usr/bin/env sh
if [ condition1 ]; then
	# Do something
elif [ condition2 ]; then
	# Do something
else
	# Do something
fi

判断某环境变量是否存在

参考:https://blog.csdn.net/blade2001/article/details/7243143?utm_source=blogxgwz3

上面的文章好像写反了

例子:判断环境变量DISPLAY是否存在(若不存在说明没有提供显示设备)

if [ "$DISPLAY" ]; then
	# DISPLAY存在
else
	# DISPLAY不存在
fi

或者

if [ ! "$DISPLAY" ]; then
	# DISPLAY不存在

字符串

功能 例子
为空 [ -z "$1" ] 或者 [ ! "$1" ]
非空 [ -n "$1" ] 或者 [ "$1" ]
相等 [ "$1" = "$2" ]
不相等 [ "$1" != "$2" ]
字典序小于 [ "$1" \< "$2" ]
字典序大于 [ "$1" \> "$2" ]

所以如果判断目录是否非空,可以这样:if [ "$(ls -A xxx)" ]

参考:https://www.cyberciti.biz/faq/linux-unix-shell-check-if-directory-empty/

整数的大小判断

代码 含义 例子
-eq = [ $1 -eq 2 ]
-ne != [ $1 -ne 2 ]
-le <= [ $1 -le 2 ]
-lt < [ $1 -lt 2 ]
-ge >= [ $1 -ge 2 ]
-gt > [ $1 -gt 2 ]
-a && [ $1 -gt 0 -a $1 -lt 10 ]
-o || [ $1 -lt 0 -o $1 -gt 10 ]

浮点数的大小判断

if awk "BEGIN {exit !(1.234 >= .233)}"; then
    echo "yes"
fi

来源:https://stackoverflow.com/a/45591665/13688160

判断文件类型

来源:https://jingyan.baidu.com/article/95c9d20d5ac536ec4e7561ad.html

#!/usr/bin/env sh
if [ -z "$1" ]; then      #如果没有输入参数,也就是第一个参数的字符串长度为0
    :                          #空语句
else
	if [ -e "$1" ]; then       #如果文件存在的话
		if [ -f "$1" ]; then   #如果文件是个普通文件?
			echo "$1 is a text file."
		elif [ -d "$1" ]; then #如果文件是个目录文件?
			echo "$1 is a directory."
		elif [ -c "$1" ]; then #如果文件是个字符设备?
			echo "$1 is a char device."
		elif [ -b "$1" ]; then #如果文件是个块设备?
			echo "$1 is a block device."
		else #否则
			echo "$1 is unknow file."
	fi
fi

另外,-s表示文件存在且不为空。来源:https://stackoverflow.com/questions/9964823/how-to-check-if-a-file-is-empty-in-bash

判断文件权限

代码 含义
-r 存在且可读
-w 存在且可写
-x 存在且可执行

参考:https://stackoverflow.com/questions/10319652/check-if-a-file-is-executable

函数

参考:https://www.runoob.com/linux/linux-shell-func.html

定义

FunctionName() {
	do_some_thing_here
	return Interger
}

也可以不return。
参数用法与脚本类似。$#表个数,$1, $9, ${10}表具体参数。

使用

FunctionName par1 par2 par3

循环

while

参考:https://wiki.jikexueyuan.com/project/shell-tutorial/shell-while-loop.html

while Command
do
   Statement(s) to be executed if Command is true
done

或者

while [ Condition ]; do
	Statement(s) to be executed if Condition is true
done

也可以对命令返回值取反,比如

while ! Command; do
	Statement(s) to be executed if Command is false
done

重定向

# 将`stdout`重定向到`stdout.txt`
Command > stdout.txt
# 将`stderr`重定向到`stderr.txt`
Command 2> stderr.txt
# 将stderr重定向到stdout
Command 2>&1
# 将stderr和stdout都重定向到一个文件
# 参考:<https://blog.csdn.net/u011630575/article/details/52151995>
Command > shell.log 2>&1
# 将`stdin`重定向到`stdin.txt`
Command < stdin.txt
# 将Command1的stdout输入到Command2的stdin
Command1 | Command2 # 例如 echo 'whoami' | sh,可以让sh执行whoami。

将多行字面量作为stdin

Command <<标记
第一行
第二行
...
标记

例如:

sh <<EOF
whoami
echo 2333
EOF

命令行参数

arg_num() {
	# 参数个数(不含$0)
	echo $#
}
# 访问某参数
echo "$2"
# 相当于arg_num "$1" "$2"
arg_num "$@"
# 相当于arg_num "$1 $2"
arg_num "$*"
shift [n]
	Shift  the  positional  parameters  n  times.  A shift sets the value of $1 to the value of $2, the value of $2 to the
	value of $3, and so on, decreasing the value of $# by one.  If n is greater than the number of positional  parameters,
	shift will issue an error message, and exit with return status 2.

n似乎默认是1。

Command substitution

把命令的输出会保存到变量:

a=$(command args...)

但如果是要把输出当字符串用,需要在周围加上双引号。但是要注意,$()之间的内容不需要再加一层转义。举个例子,判断当前目录是不是a b

check() {
	# 而不是 "$(basename \"$(pwd)\")"
	if [ "$(basename "$(pwd)")" = "a b" ]; then
		echo yes
	else
		echo no
	fi
}
check
mkdir -p "a b"
cd "a b"
check

其中"$(basename "$(pwd)")"相当于先执行basename "$(pwd)",再把输出用双引号包起来变成字符串。

如果改成"$(basename \"$(pwd)\")",就变成执行basename \"$(pwd)\",也就是先执行pwd,然后执行basename \"a b\",结果就变成a了。

相关文档:https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html

进程

获取当前subshell的PID:

pid=$(exec sh -c 'echo "$PPID"')

来源:https://unix.stackexchange.com/a/484464

set

可以用set来设置一些模式。

子命令返回值不为0时退出

set -e

但是要注意的是,对于用管道连接起来的几个命令,最终的exit code似乎是管道里的最后一个命令。例如对于command A | command B,如果command A出错返回非0,但是command B正常退出,那么这个组合命令的exit code会被设置成0,这样set -e就不会生效。

bash支持set -o pipefail,其效果是将exit code赋值为被管道组合起来的命令中最后一个返回非0值的命令,这样被管道组合起来命令中任何一个命令返回非0都会退出。

来源:Get exit status of process that's piped to another

trap

格式:

trap 命令 事件

常用事件:

  • EXIT: exit被调用

常用信号:

  • HUP: SIGHUP,父进程退出的时候会向子进程发送SIGHUP。但注意,如果父进程是被SIGKILL杀死的,那SIGHUP不一定会发送到子进程。
  • INT: SIGINT,可以由ctrl+c触发
  • TERM: SIGTERM

例子:

# a.sh
trap 'exit 1' INT
trap 'echo cleanup' EXIT
sleep 3

sh a.sh,然后ctrl+cINT事件被触发,从而调用exit 1,进而触发EXIT事件,从而调用echo cleanup,然后屏幕上会打印一行cleanup

来源:https://newbe.dev/exit-trap-in-dash-vs-ksh-and-bash

但是要注意的是,如果脚本正在执行一个外部命令,比如sleep,这时脚本里的trap是不会被调用的。因此在需要进行信号处理的脚本中如果需要执行时间很长的命令,那么要把这个命令放到子进程里跑,然后在主进程里wait。例如test.sh

#!/usr/bin/env sh
trap 'echo exit 1; exit 1' TERM
sleep 1000000
./test.sh &
pid=$!
sleep 1 
kill -TERM $pid

这时候这个进程是杀不死的,因为sleep 1000000阻塞了脚本,所以trap没有执行。但我们可以把sleep放到子进程里:

#!/usr/bin/env sh
(sleep 100000) &
pid=$!
trap 'kill -TERM $pid; echo exit 1; exit 1' TERM
wait

再执行上面的命令,这个脚本就可以被顺利杀死了。

存在的问题

不支持数组。

标签:Command,shell,笔记,echo,sh,exit,trap,https,POSIX
From: https://www.cnblogs.com/searchstar/p/18333598

相关文章

  • [vue3] Vue3源码阅读笔记 reactivity - collectionHandlers
    源码位置:https://github.com/vuejs/core/blob/main/packages/reactivity/src/collectionHandlers.ts这个文件主要用于处理Set、Map、WeakSet、WeakMap类型的拦截。拦截是为了什么?为什么要处理这些方法?Vue3实现响应式的思路是使用ProxyAPI在getter中收集依赖,在setter触发更新......
  • 学习笔记第十四天
    1.迭代器        1.1打印数组voidprintArray(int*begin,int*end){while(begin<=end){printf("%d,",*begin);++begin;}printf("\b\n");}        1.2快速排序算法voidqSort(int*begin,int*end){if(b......
  • spring boot(学习笔记第十五课)
    springboot(学习笔记第十五课)Springboot的websocket(广播)学习内容:Springboot的websocket(广播)1.Springboot的websocket(广播)回顾下webserver的进化第一代Web程序,使用整体页面刷新技术,对整个页面进行刷新。缺点:明明不需要的页面部分,也要全部刷新,对于网络带......
  • (超详细)备赛笔记 2024年全国职业院校(中职组)技能大赛(ZZ052大数据应用与服务)第一套试题
    2024年职业院校中职组ZZ052大数据应用与服务赛项赛题第01套【子任务三和四】(一)任务一:数据获取与清洗1.子任务一:数据获取(1)启动Hadoop集群,使用HDFSShell指令,在HDFS根目录下级联创建一个名为/behavior/origin_log的目录,用于存储采集到的用户行为日志;--如果......
  • Python基础知识笔记——常用函数
    一、range()函数range()函数用于生成一个整数序列。它通常用于循环结构中,例如for循环,以提供循环的迭代次数。range()函数可以有1到3个参数。#range(start,stop,step)range(2,6,2)#生成从2开始,到6结束(不包括6),步长为2的一串数字#参数指定不完全时,默认从0开始,步长......
  • 【学习笔记】并查集应用
    【学习笔记】并查集应用以NOI2001食物链为例の两种并查集用法。题目大意:规定每只动物有且仅有三种可能的种类\(A、B、C\),\(A\)会吃\(B\),\(B\)会吃\(C\),\(C\)会吃\(A\)。给定\(N\)只动物,\(K\)个语句。每个语句有如下两种可能的表达:1XY表示动物\(X\)与动......
  • pre/post gate sim 仿真笔记
    在芯片研发阶段至少存在三种仿真,只有在这三种仿真都通过后才可能进入到芯片的tapeout阶段,这三种仿真分别是rtl功能级仿真、综合后网表仿真(pregatesim)、PR后网表仿真(postgatesim)。下面简单记录一下两种gatesim仿真。不论是pre还是post的gatesim都是门级网表的仿真,进行门级......
  • c语言笔记(2024.7.24)第三天
    常量与变量概念:·表面:程序运行过程中取值可以改变的数据·实际:变量其实代表了一块内存区域/单元/空间。变量名可视为该区域的标识。整个变量分为三部分:·变量名:这个只是变量的一个标识,我们借助变量名来存取数据。·变量空间/存储单元:这个就是内存中分配的一块用来存放......
  • 位运算卷积学习笔记
    位运算卷积学习笔记位运算卷积,即快速沃尔什变换\(\text{FWT}\)和快速莫比乌斯变换\(\text{FMT}\),但事实上最常用的是\(\text{FWT}\),因为\(\text{FMT}\)所求解的内容是\(\text{FWT}\)的子集。位运算卷积首先要知道位运算卷积指的是\[c_i=\sum_{j\odotk=i}a_jb_k\]形......
  • 【调试笔记-20240730-Linux-OpenWrt 23.05 安装 Docker 配置 bitnami/Wordpress-with-
    调试笔记-系列文章目录调试笔记-20240730-Linux-OpenWrt23.05安装Docker配置bitnami/Wordpress-with-NGINX实现微信用户在线注册登录文章目录调试笔记-系列文章目录调试笔记-20240730-Linux-OpenWrt23.05安装Docker配置bitnami/Wordpress-with-NGINX实现......