【Linux】shell基本语法

1. 第一个shell程序

在hello.sh中编写shell程序

#!/bin/bash
# first command
echo hello world!
cat ~/hello.txt

其中hello.txt的文件内容为

Hello world!1
Helao world!2
Hello world!3
Hello world!4
Hello world!5
Hello world!6
abc!7

这时如果我们直接执行hello.sh文件则报错-bash: ./hello.sh: Permission denied 原因是文件没有执行权限此时执行chmod u+x hello.sh赋予权限如下

[root@bigData01 test]# ./hello.sh
-bash: ./hello.sh: Permission denied
[root@bigData01 test]# chmod u+x ./hello.sh 
[root@bigData01 test]# ./hello.sh
hello world!
Hello world!1
Helao world!2
Hello world!3
Hello world!4
Hello world!5
Hello world!6
abc!7

其实也可以通过bash ./hello.shsh ./hello.sh执行文件因为在执行的时候前面指定bash或者sh表示把hello.sh这个脚本中的内容作为参数直接传给了bash或者sh命令来执行所以这个脚本有没有执行权限都无所谓了。

2. shell中的变量

shell中的变量不需要声明初始化也不需要指定类型shell是一门弱类型的语言。shell中变量的命名要求只能使用数字、字母和下划线且不能以数字开头。

2.1 变量赋值

变量赋值是通过"="进行赋值在变量、等号和值之间不能出现空格如下(执行成功是没有反馈的只有执行错误的报错)

[root@bigData01 test]# name=cql
[root@bigData01 test]# name= cql
bash: cql: command not found...
[root@bigData01 test]# name =cql
bash: name: command not found...
[root@bigData01 test]# name_=cql
[root@bigData01 test]# name2_=cql
[root@bigData01 test]# 1name2_=cql
bash: 1name2_=cql: command not found...
[root@bigData01 test]# 1name2$=cql
bash: 1name2$=cql: command not found...

2.2 变量输出

输出变量时使用echo命令参数格式为echo $<变量名>例如输出name变量内容就可以使用echo $name命令但如果要在变量内容后面无缝链接另一个字符串haha则需要使用命令echo ${name}haha。如下

[root@bigData01 test]# echo $name
cql
[root@bigData01 test]# echo ${name}
cql
[root@bigData01 test]# echo ${name}haha
cqlhaha
[root@bigData01 test]# echo $name haha
cql haha

2.3 变量分类

2.3.1 本地变量

本地变量的格式是VAR_NAME=VALUE其实就是我们刚才在shell中那样直接定义的变量这种变量一般用于在shell脚本中定义一些临时变量只对当前shell进程有效关闭shell进程之后就消失了对当前shell进程的子进程和其它shell进程无效。
举个例子就可以证明上述描述在当前shell进程下定义本地变量name=cql然后在其他进程和当前进程的子进程中分别输出该变量若变量不存在则可以证明。如下
首先在当前进程定义本地变量输出正常

[root@bigData01 test]# name=cql
[root@bigData01 test]# echo $name
cql

在另一个新的shell进程中输出该变量内容输出为空

[root@bigData01 ~]# cd "/test"
[root@bigData01 test]# echo $name 

进入当前shell进程的子进程中输出该变量内容输出为空

[root@bigData01 test]# bash
[root@bigData01 test]# echo $name 

[root@bigData01 test]# exit
exit

2.3.2 环境变量

环境变量的定义格式为export VAR_NAME=VALUE环境变量的这种格式主要用于设置临时环境变量当你关闭当前shell进程之后环境变量就消失了对子shell进程有效对其它shell进程无效。如下

[root@bigData01 test]# export age=18
[root@bigData01 test]# echo $age
18
[root@bigData01 test]# bash 
[root@bigData01 test]# echo $name 

[root@bigData01 test]# exit
exit

若要环境变量永久生效就将export VAR_NAME=VALUE写入/etc/profile文件中并执行source /etc/profile加载文件中的命令。

2.3.3 位置变量

用于接收给shell脚本传递的参数类似与$1、$2、$3等等。举一个浅显易懂的例子
首先编写hello.sh文件内容为

#!/bin/bash
echo $0
echo $1
echo $2
echo $3

执行shell脚本

[root@bigData01 test]# hello.sh a b c d
./hello.sh
a
b
c

发现$0表示当前文件的名称$1表示脚本后的第一个参数$2表示脚本后的第二个参数等等。理论上来说脚本后面有多少个参数在脚本中就可以通过$和角标获取对应参数的值。

2.3.4 特殊变量

$# 是传给脚本的参数个数
$@ 是传给脚本的所有参数的列表
$* 是以一个单字符串显示所有向脚本传递的参数与位置变量不同参数可超过9个
$$ 是脚本运行的当前进程ID号
$? 是显示最后命令的退出状态0表示没有错误其他表示有错误
shell脚本为

#!/bin/bash
echo $0
echo $#
echo $@
echo $$
echo $?

执行结果如下

[root@bigData01 test]# hello.sh a b c
./hello.sh
3
a b c
5346
0

2.4 变量与引号

2.4.1 单引号

输出时不解析单引号中的变量如下

[root@bigData01 test]# echo $name
cql
[root@bigData01 test]# echo '$name'
$name

2.4.2 双引号

输出时解析双引号中的变量如下

[root@bigData01 test]# echo $name
cql
[root@bigData01 test]# echo "$name"
cql

2.4.3 反引号

输出时解析单引号中的变量并执行如下

反引号与$()的效果一致。

[root@bigData01 /]# name=pwd
[root@bigData01 /]# echo $name
pwd
[root@bigData01 test]# echo `$name`
/test
[root@bigData01 test]# echo $($name)
/test

3. shell中的循环

3.1 for循环

  1. for循环格式1
for((exp1; exp2; exp3))
do
    statements
done

例如:

数学算式要用(())括住。

[root@bigData01 test]# cat hello.sh 
#!/bin/bash
for((i=0;i<10;i++))
do
((sum+=i))
done
echo $sum
[root@bigData01 test]# hello.sh
45
  1. for循环格式2
for variable in value_list
do
    statements
done

例如

[root@bigData01 test]# cat hello.sh 
#!/bin/bash
# first
for i in 1 2 3 4 5 6 7 8 9
do
((sum+=i))
done
echo $sum
sum=0

# second
for i in {1..9}
do
((sum+=i))
done
echo $sum
sum=0

#third
for i in `seq 1 1 9`
do
((sum+=i))
done
echo $sum
[root@bigData01 test]# hello.sh
45
45
45

3.2 while循环

while循环格式为

while condition
do
    statements
done

例如

[root@bigData01 test]# cat while.sh 
#!/bin/bash

i=1
sum=0
while ((i <= 100))
do
    ((sum += i))
    ((i++))
done
echo "The sum is: $sum"
[root@bigData01 test]# while.sh
The sum is: 5050

4. shell中的if判断

if判断分为三个类型单分支、双分支、多分支。

4.1 单分支if语句

它的语法格式为

if  condition
then
    statement(s)
fi

例如

[root@bigData01 test]# cat if.sh 
#!/bin/bash
read a
read b
if (( $a == $b ))
then
    echo "a和b相等"
fi
[root@bigData01 test]# bash if.sh 
12
12
a和b相等

4.2 双分支if else语句

它的语法格式为

if  condition
then
   statement1
else
   statement2
fi

例如

[root@bigData01 test]# cat if.sh 
#!/bin/bash
read a
read b
if (( $a == $b ))
then
    echo "a和b相等"
else
    echo "a和b不相等输入错误"
fi
[root@bigData01 test]# bash if.sh 
12
13
a和b不相等输入错误

4.3 多分枝if elif else语句

它的语法格式为

if  condition1
then
   statement1
elif condition2
then
    statement2
elif condition3
then
    statement3
······
else
   statementn
fi

例如

[root@bigData01 test]# cat if.sh 
#!/bin/bash
printf "Input integer number: "
read num
if ((num==1)); then
    echo "Monday"
elif ((num==2)); then
    echo "Tuesday"
elif ((num==3)); then
    echo "Wednesday"
elif ((num==4)); then
    echo "Thursday"
elif ((num==5)); then
    echo "Friday"
elif ((num==6)); then
    echo "Saturday"
elif ((num==7)); then
    echo "Sunday"
else
    echo "error"
fi
[root@bigData01 test]# bash if.sh 
Input integer number: 5
Friday

5. shell后台执行

若需要在后台执行shell脚本则需要在命令后加&字符例如sh while2.sh &
但这样操作当关闭shell窗口后文件将停止运行因此若要使该程序永久在后台运行则使用nohup命令如下

[root@bigData01 test]# cat while.sh 
#!/bin/bash
while ((1>0))
do
# echo "yes"
sleep 1
done
[root@bigData01 test]# while.sh
^C
[root@bigData01 test]# while.sh &
[1] 2700
[root@bigData01 test]# ps -ef | grep while.sh
root       2700   2612  0 10:45 pts/1    00:00:00 /bin/bash ./while.sh
root       2709   2612  0 10:45 pts/1    00:00:00 grep --color=auto while.sh
[root@bigData01 test]# kill 2700
[root@bigData01 test]# ps -ef | grep while.sh
root       2717   2612  0 10:45 pts/1    00:00:00 grep --color=auto while.sh
[1]+  Terminated              while.sh
[root@bigData01 test]# nohup while.sh &
[1] 2727
[root@bigData01 test]# nohup: ignoring input and appending output to ‘nohup.out’

[root@bigData01 test]# ll
total 12
-rwxr--r--. 1 root root 199 Jan 16 21:53 hello.sh
-rw-r--r--. 1 root root 364 Jan 16 22:50 if.sh
-rw-------. 1 root root   0 Jan 17 10:45 nohup.out
-rwxr--r--. 1 root root  55 Jan 17 10:44 while.sh
[root@bigData01 test]# kill 2727

nohup命令下在后台运行的脚本只能先使用ps -ef | grep <关键字>查询pid然后通过kill命令去终止。

6. 标准输出、标准错误输出和重定向

标准输出表示是命令或者程序输出的正常信息。
标准错误输出表示是命令或者程序输出的错误信息。
重定向就是将标准输出导向一个文件或者追加到一个文件中。
其中标准输出可以使用文件描述符1来表示标准错误输出可以使用文件描述符2来表示。针对标准输出和标准错误输出可以使用重定向操作将这些输出信息保存到文件中。
例如

ll 1>a.txt表示将ll命令的标准输出重定向到a.txt文件中其中>在重定向时会覆盖文件原有内容>>表示会追加到原有内容之后。ll 1>a.txt1可以省略因为默认情况下不写也是1
lk是一个不存在的错误命令lk 2>b.txt表示会将lk命令的标准错误输出重定向到b.txt中。

[root@bigData01 test]# ll 1>a.txt
[root@bigData01 test]# cat a.txt 
total 12
-rw-r--r--. 1 root root   0 Jan 17 10:59 a.txt
-rwxr--r--. 1 root root 199 Jan 16 21:53 hello.sh
-rw-r--r--. 1 root root 364 Jan 16 22:50 if.sh
-rw-------. 1 root root   0 Jan 17 10:45 nohup.out
-rwxr--r--. 1 root root  55 Jan 17 10:44 while.sh
[root@bigData01 test]# ll 1>>a.txt
[root@bigData01 test]# cat a.txt 
total 12
-rw-r--r--. 1 root root   0 Jan 17 10:59 a.txt
-rwxr--r--. 1 root root 199 Jan 16 21:53 hello.sh
-rw-r--r--. 1 root root 364 Jan 16 22:50 if.sh
-rw-------. 1 root root   0 Jan 17 10:45 nohup.out
-rwxr--r--. 1 root root  55 Jan 17 10:44 while.sh
total 16
-rw-r--r--. 1 root root 254 Jan 17 10:59 a.txt
-rwxr--r--. 1 root root 199 Jan 16 21:53 hello.sh
-rw-r--r--. 1 root root 364 Jan 16 22:50 if.sh
-rw-------. 1 root root   0 Jan 17 10:45 nohup.out
-rwxr--r--. 1 root root  55 Jan 17 10:44 while.sh
[root@bigData01 test]# lk
bash: lk: command not found...
[root@bigData01 test]# lk 2>b.txt
[root@bigData01 test]# cat b.txt 
bash: lk: command not found...

最后再看一个综合案例
nohup hello.sh >/dev/null 2>&1 &
这条命令中各部分的含义

nohup和&可以让程序一直在后台运行
/dev/null是linux中的黑洞任何数据扔进去都找不到了
/dev/null把标准输出重定向到黑洞中表示脚本的输出信息不需要存储
2>&1 表示是把标准错误输出重定向到标准输出中

因此这条命令的意思是把脚本放在后台一直运行并且把所有输出都扔到黑洞里面。

7. 定时执行shell

  1. 在使用该服务之前先检查crontab服务状态
[root@bigData01 test]# systemctl status crond
crond.service - Command Scheduler
   Loaded: loaded (/usr/lib/systemd/system/crond.service; enabled)
   Active: active (running) since Tue 2023-01-17 10:38:35 CST; 1h 37min ago
 Main PID: 830 (crond)
   CGroup: /system.slice/crond.service
           └─830 /usr/sbin/crond -n

Jan 17 10:38:35 bigData01 systemd[1]: Started Command Scheduler.
Jan 17 10:38:36 bigData01 crond[830]: (CRON) INFO (RANDOM_DELAY will be scaled with factor 2% if used.)
Jan 17 10:38:37 bigData01 crond[830]: (CRON) INFO (running with inotify support)

看到里面的activerunning说明这个服务是启动的如果服务没有启动可以使用systemctl start crond来启动如果想要停止可以使用systemctl stop cron

  1. 查看当前定时任务
    使用命令crontab -l如下:
[root@bigData01 test]# crontab -l
no crontab for root
  1. 设置定时任务
    设置定时任务时使用命令crontab -e随后会进入一个定时任务配置文件在文件中按照格式输入命令即可。写入文件后保存退出即可若要取消该定时任务则需进入文件将命令行删除。

crontab的命令格式为
* * * * * <username> <command>
这五个*分别表示分钟0~59、小时0~23、日期1~31、月份1~12、星期数0~6如果哪一项要求每个该时间点都要执行那么就将该项数据置为*否则改为间隔时间数据。例如
每小时的第3分钟执行一次a.sh脚本文件文件地址最好写为绝对地址
7 * * * * sh /test/a.sh
每天3点执行一次a.sh脚本文件:
0 3 * * * sh /test/a.sh
每天18点30分执行一次a.sh脚本文件:
30 18 * * * sh /test/a.sh
每个月的1号的12点15分执行一次a.sh脚本文件:
15 12 1 * * sh /test/a.sh
每年的3月1号的11点45分执行一次a.sh脚本文件:
45 11 1 3 * sh /test/a.sh
每周三的16点30分执行一次a.sh脚本文件:
30 16 * * 3 sh /test/a.sh

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: shelllinux