shell 脚本
shell也是一种编程语言
定义变量 foo=bar 中间不能有空格,如foo = bar 否则会被机器认为foo是一个函数带了两个参数=和bar之后$foo可以读出foo变量里的值bar
[root@master ~]# foo=bar
[root@master ~]# echo "$foo"
bar
[root@master ~]# echo '$foo'
$foo
这里双引号 " " 会让里面可以转义的字符转义(或者说eval了一下里面的内容),但是单引号 ' ' 不会。
mcd () {
mkdir -p "$1"
cd "$1"
}
课件中mkdir里 -p的参数表示确保后面的文件存在,如果不存在就创建一个
后面的$1表示第一个参数,常见的有特殊含义的保留字如下
$0
- 脚本名$1
到$9
- 脚本的参数。$1
是第一个参数,依此类推。$@
- 所有参数$#
- 参数个数$?
- 前一个命令的返回值$$
- 当前脚本的进程识别码!!
- 完整的上一条命令,包括参数。常见应用:当你因为权限不足执行命令失败时,可以使用sudo !!
再尝试一次。$_
- 上一条命令的最后一个参数。如果你正在使用的是交互式 shell,你可以通过按下Esc
之后键入 . 来获取这个值。
bash里的||和&&和c语言中一样都是短路运算符
false || echo "Oops, fail" # Oops, fail true || echo "Will not be printed" # true && echo "Things went well" # Things went well false && echo "Will not be printed" # false ; echo "This will always run" # This will always run
命令替换 $(命令)
$(command)会被替换为命令的执行结果
如下图的$(ls)替换为了两个文件名显示了两个文件的内容$(date)被替换为了当前时间
[root@master try]# ls
example.sh mcd.sh
[root@master try]# cat $(ls)
#!/bin/bash
echo "Starting program at $(date)"
echo "Running program $0 with $# agruments with pid $$"
for file in "$@"; do
grep foobar "$file" > /dev/null 2> /dev/null
# When pattern is not found,grep has exit status
# We redirect STDOUT and STDERR to a null register
if [[ "$?" -ne 0 ]]; then
echo "file $file does not have any foobar adding one"
echo "# foobar" >> "$file"
fi
done
mcd ()
{
mkdir -p "$1"
cd "$1"
}
# foobar
进程替换(process substitution),
<( CMD )
会执行CMD
并将结果输出到一个临时文件中,并将<( CMD )
替换成临时文件名。这在我们希望返回值通过文件而不是STDIN传递时很有用。例如,diff <(ls foo) <(ls bar)
会显示文件夹foo
和bar
中文件的区别。
这是另外一种替换方式会用了可以通过文件进行输入输出
[root@master ~]# touch foo{1,2,3,4}
[root@master ~]# ls
anaconda-ks.cfg foo3 mysql80-community-release-el7-5.noarch.rpm project2
foo1 foo4 mysql-connector-java-5.1.45 project42
foo2 mcd.sh project1 try
[root@master ~]# touch foo{1,2,3,4}/test{1,2,3,4}
foo{1,2,3,4}会被扩展为foo1 foo2 foo3 foo4
bash的输入输出重定向
>
:将标准输出重定向到指定文件,会覆盖文件原有内容。>>
:将标准输出重定向到指定文件,会追加到文件末尾而不会覆盖原有内容。2>
:将标准错误重定向到指定文件,会覆盖文件原有内容。2>>
:将标准错误重定向到指定文件,会追加到文件末尾而不会覆盖原有内容。&>
:将标准输出和标准错误同时重定向到指定文件,会覆盖文件原有内容。&>>
:将标准输出和标准错误同时重定向到指定文件,会追加到文件末尾而不会覆盖原有内容。
bash的while,for,if语法
在 Bash 中,
if
、while
和for
是常用的流程控制语句,它们的基本语法如下:
- if
if condition then # code block executed if the condition is true else # code block executed if the condition is false fi
在 Bash 脚本中,
if
语句后面加分号;
是可选的,并不是必需的。在大多数情况下,可以省略这个分号,而代码仍然能够正确执行。分号
;
在 Bash 中用于分隔多个命令或语句。在if
语句的情况下,如果在then
关键字后面直接换行,Bash 会自动理解then
是单独的一条命令,不需要使用分号。
if
语句用于根据条件执行不同的代码块。condition
是一个测试表达式,如果它的返回值为 0(真),则执行then
后的代码块,否则执行else
后的代码块(如果有)。fi表示代码块的终止
- while 循环:
while condition do # code block executed while the condition is true done
循环会不断执行代码块,直到
condition
的返回值为 0(假)。每次循环开始时,都会检查condition
,如果为真,则执行循环内的代码块。当condition
为假时,循环结束。
- for 循环:
for variable in list do # code block executed for each item in the list done
for
循环用于遍历列表中的每个元素,并执行相应的代码块。variable
是一个用于存储列表中当前元素的变量,而list
是要遍历的元素列表。(支持类似c语言的for结构)这些语法规则是 Bash 中基本的流程控制结构,通过它们可以实现条件判断和循环操作。在实际使用中,可以根据具体需求组合和嵌套这些语句,以构建复杂的逻辑和循环结构。
习题解答
Solution-Shell 工具和脚本 · the missing semester of your cs education
xargs 函数
捕获一个命令的输出传递给另外一个命令,和管道一起使用-d的参数表示分隔符的选择,如习题里分隔符应该选择'\n'换行符而不是空格。
这段命令是一个用于查找当前目录下的所有文件,并按照修改时间进行排序后,输出最近修改的文件的信息的命令。
find . -type f -print0 | xargs -0 ls -lt | head -1命令的解释
让我们逐步解释这个命令:
find . -type f -print0
: 这部分使用find
命令来查找当前目录(.
)下的所有文件(不包括目录)。-type f
表示只查找文件,而不包括目录。-print0
表示以 null 字符(\0)作为文件名的分隔符输出结果,这样可以正确处理文件名中包含空格或特殊字符的情况。
|
: 这是管道符号,它将find
命令的输出传递给下一个命令。
xargs -0 ls -lt
: 这部分使用xargs
命令将find
的输出作为参数传递给ls
命令。-0
表示以 null 字符作为参数的分隔符,与find
命令中的-print0
对应。ls -lt
表示以长格式(详细信息)列出文件,并按照修改时间从最新到最旧进行排序。-l表示详细信息-t表示按时间排序
head -1
: 最后,使用head
命令仅显示排序后的结果的前一行,也就是显示最近修改的文件信息。-mmin 60表示最近60分钟内修改的信息
可能会提示因信号13而终止,因为使用了head 函数在head已经捕获了需要的输入之后xargs仍然在输入引起的管道破裂