Linux Shell 编程基础语法汇总

读 Jetson 脚本

把脚本设置为可执行

假设要将脚本 test.sh 设置为可执行,需要:

  1. 使用 chmod +x test.sh 改变文件模式为可执行;
  2. 使用 ./ 指定路径,比如先将当前工作区设置为脚本所做位置(使用 cd 命令),然后: ./test.sh

如果执行时出现异常信息:/bin/sh^M: bad interpreter: No such file or directory
原因:
是我们在 windows 下编写的脚本文件,直接放到 Linux 默认的是 dos 模式的文本,不被识别,需要处理下。
解决办法有 3 种:

  1. 用 vim 打开脚本文件,在命令模式下输入::set ff=unix, 然后输入 :wq 保存退出就可以了。(set ff=unix 是告诉 Vim,将文件的换行符从原来的格式转换为 Unix 格式。)
  2. 在 windows下转换脚本格式,用 Notepad 改变文件格式即可。File–>Conversions–>DOS->UNIX
  3. 在 Linux 下新建一个 .sh 文件,然后复制粘贴过去也是可以的。

感谢网友 QC(_) 的博文。

2、在 windows下转换脚本格式,用 Notepad 改变文件格式即可。File–>Conversions–>DOS->UNIX。

3、在 Linux 下新建一个 .sh 文件,然后复制粘贴过去也是可以的。

————————————————
版权声明:本文为CSDN博主「QC(_)」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_27195727/article/details/115698995

脚本参数 ${0}${1}${2}${3}${#}${@}

${0} 表示脚本或函数的名称。
${1}${2}${3} 等表示脚本或函数的第一、第二、第三个参数,以此类推。
${#} 表示传递给脚本的参数个数
`${@} 表示列出所有参数
举一个例子:

#!/bin/bash

echo "Shell name: ${0}."
echo "Number of parameters: ${#}."
echo "The first parameter is ${1}."
echo "The second parameter is ${2}."
echo "The parameter list is ${@}."
exit 0

脚本命名为 shell_arg.sh,运行这个脚本:
./shell_arg.sh 1 2 3

输出内容为:
Shell name: ./shell_arg.sh.
Number of parameters: 3.
The first parameter is 1.
The second parameter is 2.
The parameter list is 1 2 3.

注意的是,¥{0} 会包含脚本的路径。

命令替换 $() 与命令 basename

$() 表示命令替换。这是一种特殊的变量,它会将括号内的命令执行的结果赋值给变量。

#!/bin/bash

script_name="$(basename "${0}")"
echo "${script_name}"
exit 0

运行这个脚本:./shell_arg.sh
输出内容为:shell_arg.sh

在这个例子中,命令 basename 用于提取文件路径中的文件名,并显示基本文件名。
具体而言,basename命令从文件路径中删除目录路径和符号链接,只保留文件名部分。这对于提取文件名而不需要完整的文件路径非常有用。
比如 basename /path/to/file.txt ,输出的内容为 file.txt

命令 readlinkdirname

readlink 命令用于读取符号链接(symbolic link)所指向的实际文件路径。

符号链接是一种特殊类型的文件,它包含了另一个文件或目录的引用。当读取符号链接时,实际上读取的是链接目标文件的路径,而不是链接文件本身。readlink命令允许用户通过解析符号链接来获取实际文件的路径。语法为:

readlink [-fhlnr] [-m pattern] [file...]

主要选项和功能如下:

-f:解析路径名中的符号链接,并将其替换为实际路径。
-l:将输入作为符号链接对待,而不是普通文件。
-n:不进行换行处理,将输出直接打印到标准输出。
-r:递归解析符号链接,直到找到最终目标。
-m:使用模式匹配来解析符号链接。

dirname 是一个常用的命令行工具,它用于提取文件路径中的目录部分。

具体来说,dirname 命令接受一个文件路径作为参数,并返回该路径所在的目录路径。它删除了文件名和文件扩展名部分,只保留目录路径。

#!/bin/bash

script_name="$(basename "${0}")"
script_path="$(readlink -f "${0}")"
script_dir="$(dirname "${script_path}")"
echo "${script_name}"
echo "${script_path}"
echo "${script_dir}"
exit 0

运行这个脚本:./shell_arg.sh
输出内容为:
script_name is shell_arg.sh
script_path is /home/zhzhchang/Documents/Vscode-shell-test/shell_arg.sh
script_dir is /home/zhzhchang/Documents/Vscode-shell-test

if 语句的测试条件

在Linux shell编程中,if语句可以用于进行条件测试。以下是常见的测试条件:

  1. 文件测试:

    • -f:检查文件是否存在且是一个普通文件。
    • -d:检查目录是否存在。
    • -e:检查文件或目录是否存在。
    • -r:检查文件是否可读。
    • -w:检查文件是否可写。
    • -x:检查文件是否可执行。
    • -h:文件或目录是否是符号链接
  2. 字符串测试:

    • -z:检查字符串是否为空。
    • -n:检查字符串是否非空。
  3. 整数比较:

    • -eq:等于
    • -ne:不等于
    • -lt:小于
    • -gt:大于
    • -le:小于等于
    • -ge:大于等于
  4. 逻辑测试:

    • -a:与(AND)
    • -o:或(OR)
    • !:非(NOT)
  5. 字符串比较:

    • =:字符串相等
    • !=:字符串不相等
    • -z!= 非空字符串(长度为零)
    • -n!= 空字符串(长度非零)
  6. 数值比较(需使用双括号):

    • ((a == b)):等于
    • ((a != b)):不等于
    • ((a < b)):小于
    • ((a > b)):大于
    • ((a <= b)):小于等于
    • ((a >= b)):大于等于需要使用双括号来表示数值比较。

set -eset +e

set -e 是一个用来设置脚本行为的命令。当脚本遇到任何错误时,它将会立即终止脚本的执行。set -e 通常用在脚本的开始部分,以确保脚本在遇到任何错误时能够立即停止,这样可以帮助开发者更快地定位和修复问题。

set +e 用于取消上述设置。

退出状态码:$?

在Unix和类Unix系统中,每个运行中的进程都有一个退出状态码(也称为返回值),当进程结束时返回给操作系统。这个退出状态码可以用来表示进程是否成功地完成了它的任务,或者是否遇到了错误。在 shell 脚本中,你可以使用 $? 来检查上一条命令的退出状态,以此为基础来决定下一步的操作。通常,0 表示成功,非零值 表示错误。

延时:sleepusleep

Linux shell环境下,常用的延时函数包括:

  1. sleep:秒延时。函数原型为 unsigned int sleep(unsigned int seconds)。例如:sleep(1) 表示延时一秒。
  2. usleep:微秒延时。函数原型为 int usleep(useconds_t usec)。注意,usec 需要小于 1000000。例如,usleep(1000) 表示延时 1 秒(1000 微秒)。

捕获和处理信号 trap

function cleanup() {
# ...
}
trap cleanup EXIT

在Shell脚本中,trap 是一个内置命令,用于捕获和处理信号。这里的 trap cleanup EXIT 意味着当脚本收到 EXIT 信号(通常是在脚本完成或由于某种错误导致脚本中断时发送的)时,它会执行 cleanup 函数。

信号的名字定义在头文件 signal. h 中,

  1. EXIT:退出,在脚本完成或由于某种错误导致脚本中断时发送的退出信号。
  2. INT:中断,当用户按下Ctrl+C时,会发送中断信号。
  3. QUIT:退出,当用户按下Ctrl+\时,会发送退出信号。
  4. ABRT:中止,通常印某些严重的错误而引发
  5. ALRM:报警,通常用于处理超时
  6. TERM:终止,通常在系统关机时发送

参数列表左移动:shift

在Shell脚本中,shift 命令用于将参数列表向左移动。shift 2 的意思是将参数列表向左移动两位。举个例子,如果你有如下的参数列表:arg1 arg2 arg3 arg4,执行 shift 2 后,原来的 arg1arg2 会被丢弃,新的参数列表变成:arg3 arg4

内置命令 source

作用有点类似于 C 中的 #include 指令,具体来说,当你在 source 命令后指定一个文件名(例如 source test.sh ),Shell 会首先读取 test.sh 文件中的所有命令,然后将这些命令插入到当前 Shell 环境中执行。这意味着,文件中定义的任何变量或函数都可以在当前 Shell 环境中直接使用。

source 命令的一个常见用途是加载环境变量。如果你修改了 .bashrc 或其他配置文件,你可以使用 source 命令让这些修改立即生效,而无需重新登录。例如,你可以在 .bashrc 文件中设置某些环境变量,然后在你需要这些环境变量的 Shell 会话中使用source 命令加载它们。

当前目录压栈并切换到新目录:pushd

在 Shell 中,pushd 是一个命令,用于将当前目录压入目录栈,并切换到指定的目录。具体而言,pushd 会将当前目录的路径保存到栈中,然后通过改变当前工作目录来切换到指定的目录。

以通过 popd 命令返回之前的目录。

需要注意的是,pushdpopd 命令是针对当前 Shell 会话的,而不是针对脚本本身。这意味着在脚本中执行这些命令只会影响当前 Shell 会话中的工作目录,而不会影响脚本执行完毕后的工作目录。

重定向标准输出和标准错误

  1. 将标准输出重定向到文件:
command > output.txt

这将执行 command 并将输出写入 output.txt 文件中。如果文件不存在,则会创建该文件;如果文件已存在,则会覆盖其内容。

  1. 将标准输出追加到文件的末尾:
command >> output.txt

类似于上面的方法,但是输出将追加到 output.txt 文件的末尾,而不是覆盖文件内容。

  1. 将标准输出和错误输出同时重定向到文件:
command > output.txt 2>&1

这会将标准输出和错误输出都重定向到 output.txt 文件中。2>&1 表示将标准错误(file descriptor 2)重定向到标准输出(file descriptor 1)。

  1. 将标准输出和错误输出都重定向到 /dev/null,也就是说,不显示任何输出信息:
command > /dev/null 2>&1

取出等号前的内容

cut -d'=' -f1

是一个用于处理文本的命令。这个命令的作用是按等号( ‘=’ )作为分隔符( -d 选项指定),选择每行的第一个字段( -f1 选项指定)。通常,这个命令用于处理键值对文本,例如在处理 INI 文件或环境变量导出时,它能提取出等号前的键。

生成随机密码

user_pass="$(date +%s | sha256sum | base64 | head -c 8)"

这段代码是在 Bash shell 环境中生成一个用户密码。它的工作方式如下:

  1. date +%s:这部分生成一个当前时间的 Unix 时间戳。

  2. sha256sum:这个命令对前面生成的时间戳进行 SHA-256 哈希运算。

  3. base64:这个命令将上一步的哈希结果进行 Base64 编码,使其变成一个可打印的字符。

  4. head -c 8:最后这个命令从编码后的结果中选取前8个字符。

因此,这段代码生成的是一个8个字符长度的Base64编码的SHA-256哈希值,它基于当前的Unix时间戳。这样的用户密码由于其随机性和基于时间的特性,可以提供较好的安全性。

获取参数列表中最后一个参数

nargs=$#;
target_rootdev=${!nargs};
  • $#是特殊的Shell变量,代表命令行参数的个数,这就是 nargs 的值。
  • ${!nargs} 是间接引用,它引用的是 nargs 变量的值所代表的变量。在这个上下文中,nargs 的值是$#,代表命令行参数的个数,因此 ${!nargs} 就引用了第 $# 个参数。

解析命令行参数

opstr+="b:c:d:e:f:h:i:k:m:n:o:p:rs:t:u:v:w:x:z:B:C:F:G:I:K:L:M:N:P:R:S:Z:-:";
while getopts "${opstr}" OPTION; do
	case $OPTION in
	b) BCTFILE=${OPTARG}; ;;
	Z) zflag="true"; ;;			# cmdline only
	-) case ${OPTARG} in
	   no-root-check) no_root_check=1; ;;
	   no-flash) no_flash=1; ;;
	   esac;;
	*) usage allunknown 1; ;;
	esac;
done
  1. opstr+="b:c:d:e:f:h:i:k:m:n:o:p:rs:t:u:v:w:x:z:B:C:F:G:I:K:L:M:N:P:R:S:Z:-:";:这一行定义了一个字符串 opstr,并向其添加了多个字符,每个字符后面都有一个冒号。这些字符将作为选项用于后面的 getopts 命令。
  2. while getopts "${opstr}" OPTION; do:这是一个 while 循环,它将遍历通过 opstr 定义的每个选项。getopts 命令将解析命令行参数,并将每个选项的名称存储在变量 OPTION 中。
  3. case $OPTION in:这是一个 case 语句,它将根据 OPTION 的值来执行不同的操作。

接下来,代码定义了与每个选项对应的操作。例如,当选项是 b 时,将把变量 BCTFILE 设置为命令行参数的值。类似的,对于其他选项也有类似的操作。

  1. *) usage allunknown 1; ;;):这是一个通配符模式,用于处理不匹配任何特定选项的情况。在这种情况下,将执行 usage allunknown 1 命令,但该命令在给定的代码段中没有定义。
  2. esac; done:这是 case 语句和 while 循环的结束标记。

另外,在选项 - 的情况下,根据命令行参数的值,将执行不同的操作。例如,如果参数是 no-root-check,则将变量 no_root_check 设置为1,以此类推。

这个脚本主要用于处理命令行参数,并根据参数的值执行相应的操作。

检查函数是否存在

declare -F -f process_fuse_level > /dev/null 2>&1;

这段代码用于检查是否存在一个名为 process_fuse_level 的函数。

declare -F -f process_fuse_level 这句代码会检查是否存在名为 ‘process_fuse_level’ 的函数,如果存在,该函数会被声明为只读。

然后 /dev/null 2>&1 将标准输出和错误输出都重定向到 /dev/null,也就是说,不显示任何输出信息。
总的来说,这段代码用于在不产生任何输出(包括错误)的情况下检查一个函数是否存在。

查找并分割字符串

tegrarcm --uid | grep BR_CID | cut -d' ' -f2
  1. 命令 tegrarcm --uid 输出的信息为:BR_CID: 0x32101001642a170814000000120204c0
  2. grep 命令用于搜索文本,在给定的文件或标准输入中搜索匹配 ‘BR_CID’ 的行,其输出通过管道传送给 cut 命令
  3. cut 命令用于从文本中提取字段,这里的 -d' ' 指定了字段分隔符为空格,-f2 表示提取第二个字段。因此,cut 命令将从 grep 命令输出的每一行中提取第二个字段(以空格分隔),并将其输出到标准输出。
  4. 最终输出为:0x32101001642a170814000000120204c0

字符串切片

ECID="0x32101001642a170814000000120204c0";
flval="${ECID:2:1}"
  1. 第一行定义了一个名为 ECID 的变量,并赋值为一个十六进制的字符串。
  2. flval="${ECID:2:1}":这一行使用了字符串切片操作。${ECID:2:1} 表示从 ECID 的第 2 个字符开始(索引从 0 开始计算),截取长度为 1 的片段。所以这行代码将 ECID 的第 3 个字符(在 ECID 中索引为 2 的字符)赋值给 flval

这段代码在 ECID 为 “0x32101001642a170814000000120204c0” 的情况下,flval 的值将是 “3”。

默认参数扩展 :-

ROOTFS_TYPE="${ROOTFS_TYPE:-ext4}";

这行 Shell 代码定义了一个变量 ROOTFS_TYPE,如果 ROOTFS_TYPE 这个变量在之前已经定义过,并且其值不是空字符串,那么这行代码就不会改变 ROOTFS_TYPE 的值。但如果 ROOTFS_TYPE 这个变量之前没有定义,或者其值为空字符串,那么这行代码就会将其值设置为 ext4。这是 Shell 中的默认参数扩展(Parameter Expansion)的用法。

执行存储在字符串中的命令:eval

eval 命令用于执行存储在字符串中的命令,并返回结果。

这个命令会解析并执行其参数指定的字符串中的命令,然后将结果输出到标准输出。例如,如果你有一个字符串包含了一个命令,你可以使用 eval 来执行那个命令。

注意,由于 eval 会执行字符串中的任意命令,因此在使用时需要特别小心,避免执行不安全的命令。

定义空数组

pre_deb_list=()

最小化 Jetson 磁盘

负载测试:fio

#读测试
fio -filename=test2g -direct=1 -rw=read -bs=1M -size=2G -numjobs=64 -runtime=10 -group_reporting -name=file1

#写测试
fio -filename=test2g -direct=1 -rw=write -bs=1M -size=2G -numjobs=64 -runtime=10 -group_reporting -name=file1
  • -filename=test2g: 指定测试的文件名为’test2g’。注意会在工作目录下生成 test2g 文件,测试完成后要手动删除
  • -direct=1: 直接I/O模式,绕过页缓存。
  • -rw=read: 测试读取操作,替换之前的write。
  • -rw=write表示这是写入测试
  • -bs=1M: 块大小设为1M。
  • -size=2G: 测试的文件大小为2G。
  • -numjobs=64: 同时进行的作业数设为64。
  • -runtime=10: 每个作业运行10秒。
  • -group_reporting: 启用组报告模式,可以同时报告所有作业的总体情况。
  • -name=file1: 给这个测试任务命名为’file1’。
fio-3.1
Starting 64 processes
file1: Laying out IO file (1 file / 2048MiB)
Jobs: 64 (f=64): [R(64)][100.0%][r=88.0MiB/s,w=0KiB/s][r=88,w=0 IOPS][eta 00m:00s]
file1: (groupid=0, jobs=64): err= 0: pid=4780: Thu Mar  2 15:07:30 2023
   read: IOPS=88, BW=88.8MiB/s (93.1MB/s)(952MiB/10722msec)
    clat (msec): min=14, max=10702, avg=695.81, stdev=2470.19
     lat (msec): min=14, max=10702, avg=695.81, stdev=2470.19
    clat percentiles (msec):
     |  1.00th=[   22],  5.00th=[   23], 10.00th=[   23], 20.00th=[   23],
     | 30.00th=[   23], 40.00th=[   23], 50.00th=[   23], 60.00th=[   23],
     | 70.00th=[   23], 80.00th=[   23], 90.00th=[  372], 95.00th=[ 9597],
     | 99.00th=[10537], 99.50th=[10671], 99.90th=[10671], 99.95th=[10671],
     | 99.99th=[10671]
   bw (  KiB/s): min= 2048, max=47772, per=25.31%, avg=23012.47, stdev=21602.27, samples=80
   iops        : min=    2, max=   46, avg=22.20, stdev=20.83, samples=80
  lat (msec)   : 20=0.11%, 50=88.97%, 500=2.10%, 750=2.31%, >=2000=6.51%
  cpu          : usr=0.00%, sys=0.07%, ctx=1095, majf=0, minf=17569
  IO depths    : 1=100.0%, 2=0.0%, 4=0.0%, 8=0.0%, 16=0.0%, 32=0.0%, >=64=0.0%
     submit    : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
     complete  : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
     issued rwt: total=952,0,0, short=0,0,0, dropped=0,0,0
     latency   : target=0, window=0, percentile=100.00%, depth=1

Run status group 0 (all jobs):
   READ: bw=88.8MiB/s (93.1MB/s), 88.8MiB/s-88.8MiB/s (93.1MB/s-93.1MB/s), io=952MiB (998MB), run=10722-10722msec

Disk stats (read/write):
  mmcblk0: ios=1886/1, merge=0/3, ticks=1126360/4332, in_queue=1321704, util=98.65%

统计根目录下所有文件夹的大小

sudo du -ah --max-depth=1 /
  • -a:显示所有的文件和目录,而不是只显示目录的总大小
  • -h:以人类可读模式显示(使用 K、M、G 等单位)
  • --max-depth:限制递归深度为 1。
  • /:从根目录开始计算

列出已经安装的软件包(带大小)

dpkg-query -Wf '${Installed-Size;8} KiB \t${Package;-30}\t${binary:Summary}\n'

按照软件包大小排序列出所有已经安装的软件

dpkg-query -Wf '${Installed-Size;8} KiB \t${Package;-30}\t${binary:Summary}\n' | sort -n -t$'\t' -k 1,1

你可能感兴趣的:(Linux,linux,Shell)