Shell Syntax Basic
Shell Syntax Basic
Variables
在shell
中并不需要提前声明变量,每次使用的时候自动生成,并且所有变量在默认的情况下都是字符串。Linux
对于变量的大小写敏感,因此需要格外注意。
通过 $
运算符,可以访问变量的内容,声明变量有两种方式:
- 直接赋值;
var="content in var"
read
方法
read var
> type contents here to assign
通常在bash
中会使用空格来分割不同的命令、语句,如果希望给变量赋值的时候带一个空格,需要用"..."
来包含;同时,如果希望通过变量的值替换 $var
则需要用双引号,而如果不期望替换的话,用单引号或者转义字符。
环境变量 Environmentt Variables
Environment Variable | Description |
---|---|
$HOME |
The home directory of the current user |
$PATH |
A colon-separated list of directories to search for commands |
$PS1 | A command prompt, frequently $ , but in bash you can use some more complex values; for example, the string [\u@\h \W]` |
Environment Variable |
-------------------- | ------------------------------------------------------------ |
is a popular default that tells you the user, machine name, and current directory, as well as providing a $ prompt. | |
$PS2 |
A secondary prompt, used when prompting for additional input; usually >. |
$IFS |
An input field separator. This is a list of characters that are used to separate words when the shell is reading input, usually space, tab, and newline characters. |
$0 |
The name of the shell script |
$# |
The number of parameters passed |
`$ | Environment Variable |
-------------------- | ------------------------------------------------------------ |
| The process ID of the shell script, often used inside a script for gener- ating unique temporary filenames; for example /tmp/tmpfile_$$ |
通过 man env
可以查看如何通过 export
设置环境变量。
Parameter Variables
如果在调用脚本的时候,带有命令行参数,则会自动生成一些变量,如果没有传递参数,则 $#
返回 0;
Parameter Variable | Description |
---|---|
$1, $2, … |
The parameters given to the script |
$* | A list of all the parameters, in a single variable, separated by the first character in the environment variable IFS. If IFS is modified, then the way $* separates the command line into parameters will change. |
|
$@ | A subtle variation on $*; it doesn’t use the IFS environment vari- able, so parameters are not run together even if IFS is empty. |
#!/bin/sh
salutation=”Hello”
echo $salutation
echo “The program $0 is now running”
echo “The second parameter was $2”
echo “The first parameter was $1”
echo “The parameter list was $*“
echo “The user’s home directory is $HOME”
echo “Please enter a new greeting”
read salutation
echo $salutation
echo “The script is now complete”
exit 0
Output
$ ./try_var foo bar baz Hello The program ./try_var is now running The second parameter was bar The first parameter was foo The parameter list was foo bar baz The user’s home directory is /home/rick Please enter a new greeting >Sire Sire The script is now complete $
Conditions
Shell
脚本可以检测所有命令行可以激活的命令的返回值,所以每次书写 Shell 脚本的时候带上返回值是很重要的。
The test or [ Command
Shell 语句通过 [ 检查布尔值,在书写的时候,方括号前后必须有空格,可以把 test 和 方括号当作同义词,因为在使用test的时候还会带上空格。如果希望把 if ... then
语句放在同一行,则必须在方括号条件值后面加上一个分号。
#!/bin/sh
if [ -f /bin/bash ]; then
echo “file /bin/bash exists”
fi
if [ -d /bin/bash ]; then
echo “/bin/bash is a directory”
else
echo “/bin/bash is NOT a directory”
fi
条件类型可以用来做三件事:
- 字符串比较
String Comparison | Result |
---|---|
string1 = string2 |
True if the strings are equal |
string1 != string2 |
True if the strings are not equal |
-n string |
True if the string is not null |
-z string |
True if the string is null (an empty string) |
- 算数比较
Arithmetic Comparison | Result |
---|---|
expression1 -eq expression2 |
True if the expressions are equal |
expression1 -ne expression2 |
True if the expressions are not equal |
expression1 -gt expression2 |
True if expression1 is greater than expression2 |
expression1 -ge expression2 |
True if expression1 is greater than or equal to expression2 |
expression1 -lt expression2 |
True if expression1 is less than expression2 |
expression1 -le expression2 |
True if expression1 is less than or equal to expression2 |
! expression |
True if the expression is false, and vice versa |
- 文件状态比较
File Conditional | Result |
---|---|
-d file |
True if the file is a directory |
-e file |
True if the file exists. Note that historically the -e option has not been portable, so -f is usually used. |
-f file |
True if the file is a regular file |
-g file |
True if set-group-id is set on file |
-r file |
True if the file is readable |
-s file |
True if the file has nonzero size |
-u file |
True if set-user-id is set on file |
-w file |
True if the file is writable |
-x file |
True if the file is executable |
Program control
if
#!/bin/sh
echo “Is it morning? Please answer yes or no”
read timeofday
if [ $timeofday = “yes” ]; then
echo “Good morning”
else
echo “Good afternoon”
fi
exit 0
Elif
用于给 if 控制符添加第二个条件,请看例子
...
if [ $timeofday = "yesy" ]; then
echo ...
elif [ $timeof = "no" ]; then
echo ...
else
echo ...
exit 1
if
exit 0
当直接敲入回车的时候,此程序会有bug,因为没有字符串与 “yes” 进行比较,因此最好把 $timeofday 用双引号扩起来,这样就必有一个字符串与 “yes” 进行比较了。
For
用for巡护眼可以在一个字符串集合的基础上,控制循环,这个集合通常是一堆文件名。
for variable in values
do
statements
done
在使用 for 循环的时候,使用通配符,可以大幅度的简化程序,并且不丧失可读性。
#!/bin/sh
for file in $(ls f*.sh); do
lpr $file
done
exit 0
while
当不知道循环次数的时候,一般没法用 for 循环,而要使用 while 循环;
while condition do
statements
done
=========================================================================================
#!/bin/sh
echo "Enter password"
read trythis
while [ "$trythis" != "secret" ]; do
echo "sorry, try again"
read trythis
done
exit 0
case statement
#!/bin/sh
echo “Is it morning? Please answer yes or no”
read timeofday
case “$timeofday” in
yes) echo “Good Morning”;;
no) echo “Good Afternoon”;;
y) echo “Good Morning”;;
n) echo “Good Afternoon”;;
================================================
yes | y | Yes | YES ) echo "Good morning";;
n* | N* ) echo "Good Afternoon";;
* ) echo "Sorry, answer not recognized";;
================================================
[yY] | [Yy][Ee][Ss] ) ...
[nN]* ) echo "Good Afternoon";;
================================================
*) echo “Sorry, answer not recognized”;;
esac
exit 0
Lists
The "AND" List
statement_1 && statement_2 && statement_3 && ...
且列表允许用户执行一系列命令,仅当之前的命令全部执行了,才可以执行下一个(从最左边开始)。
The "OR" List
statement_1 || statement_2 || ...
从左至右执行,直到有一个执行成功,则不再执行。下一个命令如果想要执行,则上一个命令必须失败。
Functions
在使用一个函数之前,必须要首先定义它,定义的方式与其他语言差不多:
#!/bin/bash
foo() {
echo "Function foo is executing!"
}
foo
exit 0
当唤醒一个函数的时候,$*, $@, $#, $1$
等变量会被函数变量替代,当函数执行结束,又会恢复到原有值。使用 return
关键字可以让函数返回数值,若希望函数返回字符串,要们新建一个字符串用于存储返回字符串,要么使用 echo
语句:
foo(){
echo STRING_HERE
}
...
result="$(foo)"
函数返回值
下面的例子说明了如何传递值给函数,并且返回结果。
#!/bin/sh
yes_or_no() {
echo "Is this your name $* ?"
while true
do
echo -n "Enter yes or no: "
read x
case "$x" in
y | yes ) return 0;;
n | no ) return 1;;
* ) echo "Answer yes or no"
esac
done
}
echo "Original parameters are $*"
if yes_or_no "$1"
then
echo "Hi, $1, nice name"
else
echo "Never mind"
fi
exit 0
Commands built into the shell
You can execute two types of commands from inside a shell script. There are “normal” commands that you could also execute from the command prompt (called external commands), and there are “built-in” commands (called internal commands), as mentioned earlier. Built-in commands are implemented internally to the shell and can’t be invoked as external programs. However, most internal commands are also provided as standalone programs — this requirement is part of the POSIX specification. It generally doesn’t matter if the command is internal or external, except that internal commands execute more efficiently.
Two Useful Commands and Regular Expressions
Find 命令
- -name
按照文件名查找文件。
find /dir -name filename
在/dir目录及其子目录下面查找名字为filename的文件
find . -name "*.c"
在当前目录及其子目录(用“.”表示)中查找任何扩展名为“c”的文件 - -type
查找某一类型的文件,诸如:
b - 块设备文件。
d - 目录。
c - 字符设备文件。
p - 管道文件。
l - 符号链接文件。
f - 普通文件。
find /etc -type d –print
在/etc目录下查找所有的目录
find . ! -type d –print
在当前目录下查找除目录以外的所有类型的文件
find /etc -type l –print
在/etc目录下查找所有的符号链接文件 - -size n:[c] 查找文件长度为n块的文件,带有c时表示文件长度以字节计。
find . -size +1000000c –print
在当前目录下查找文件长度大于1 M字节的文件
find /home/apache -size 100c –print
在/home/apache目录下查找文件长度恰好为100字节的文件
find . -size +10 –print
在当前目录下查找长度超过10块的文件(一块等于512字节) - -depth:在查找文件时,首先查找当前目录中的文件,然后再在其子目录中查找。
find / -name "CON.FILE" -depth –print
它将首先匹配所有的文件然后再进入子目录中查找 - -mount:在查找文件时不跨越文件系统mount点。
find . -name "*.XC" -mount –print
从当前目录开始查找位于本文件系统中文件名以XC结尾的文件(不进入其他文件系统) - -follow:如果find命令遇到符号链接文件,就跟踪至链接所指向的文件。
- -mtime -n +n
按照文件的更改时间来查找文件, - n表示文件更改时间距现在n天以内,+ n表示文件更改时间距现在n天以前。
find / -mtime -5 –print
在系统根目录下查找更改时间在5日以内的文件
find /var/adm -mtime +3 –print
在/var/adm目录下查找更改时间在3日以前的文件
Find with xargs
find . -type f -print | xargs file
查找系统中的每一个普通文件,然后使用xargs命令来测试它们分别属于哪类文件
find / -name "core" -print | xargs echo "" >/tmp/core.log
在整个系统中查找内存信息转储文件(core dump) ,然后把结果保存到/tmp/core.log 文件中:
find . -type f -print | xargs grep "hostname"
用grep命令在所有的普通文件中搜索hostname这个词
find ./ -mtime +3 -print | xargs rm -f –r
删除3天以前的所有东西 (find . -ctime +3 -exec rm -rf {} ;)
find ./ -size 0 | xargs rm -f &
删除文件大小为零的文件
find命令配合使用exec和xargs可以使用户对所匹配到的文件执行几乎所有的命令。
Grep - global search regular expression and print out the line
grep [OPTIONS] PATTERN [FILE...]
grep [OPTIONS] [-e PATTERN | -f FILE] [FILE...]
^pattern
: 以 pattern 开头的行;pattern$
: 以 pattern 结尾的行;patte.n
: 匹配一个非换行符的字符;pat*n
: 匹配零个或多个先前字符;[pattern]
: 匹配一个指定范围内的字符;[^pattern]
: 匹配一个不在指定范围内的字符;\<pattern
: 匹配包含以 pattern 开头的单词 的行;\>
: 锚定单词的结束;
可选参数
- -?:同时显示上下?的行;
- -c:只打印匹配的行术,不限时匹配的内容;
- -h:搜索多个文件时,不显示匹配文件名前缀;
- -n:在匹配行的前面打印行号;
- -s:不限时不存在或者无法读取的错误信息;
- -v:只显示不匹配的行;
例子
ls -l | grep '^a'
通过管道过滤ls -l输出的内容,只显示以a开头的行。
grep 'test' d*
显示所有以d开头的文件中包含test的行。
grep 'test' aa bb cc
显示在aa,bb,cc文件中匹配test的行。
grep '[a-z]' aa
显示所有包含每个字符串至少有5个连续小写字符的字符串的行。
grep 'w(es)t.*' aa
如果west被匹配,则es就被存储到内存中,并标记为1,然后搜索任意个字符(.),这些字符后面紧跟着另外一个es(),找到就显示该行。如果用egrep或grep -E,就不用""号进行转义,直接写成'w(es)t.'就可以了。
grep -i pattern files
:不区分大小写地搜索。默认情况区分大小写
grep -l pattern files
:只列出匹配的文件名,
grep -L pattern files
:列出不匹配的文件名,
grep -w pattern files
:只匹配整个单词,而不是字符串的一部分(如匹配‘magic’,而不是‘magical’),
grep -C number pattern files
:匹配的上下文分别显示[number]行,
grep pattern1 | pattern2 files
:显示匹配 pattern1 或 pattern2 的行,
grep pattern1 files | grep pattern2
:显示既匹配 pattern1 又匹配 pattern2 的行。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了