《Linux命令行与shell脚本编程大全》笔记1

使用多个命令
运行多个命令,可以把它们放在同一行彼此之间用分号隔开。
date;who

创建shell脚本文件
第一行 #!/bin/bash
在shell脚本中,(# )用作注释行,#后的!会告诉shell用哪个shell来运行脚本
让shell找到脚本的方法:用绝对或相对文件路径来引用shell脚本;将shell脚本文件所在的目录添加到PATH环境变量中。./test1
修改脚本可执行权限:chmod +x test1

显示消息
echo命令
echo string,默认情况下不需要使用双引号将要显示的文本字符串划定出来
echo This is a test
如果字符串出现引号:

echo "Let's see if this'll work"
echo 'Rich says "scripting is easy".'

如果想把文本字符串和命令输在同一行,使用echo -n

echo -n "The time and date are: "
date

环境变量
显示一份完整的当前环境变量列表
set
使用环境变量:$variable

echo "User info for userid: $USER"
echo UID:$UID
echo HOME:$HOME

在脚本显示美元符号:$

用户变量
用户变量名区分大小写
创造变量:变量名=变量值 (变量、等号和值之间不能出现空格)
使用变量:$变量名

days=10
guest="keiji"
echo "$guest checked in $days days ago"
value1=100

#将value1的值赋给value2
value2=$value1 

命令替换
两种方法:

`command`
$(command)
例子:
testing=`date`
testing=$(date)
echo "The date and time are: " $testing

写一个脚本,用过命令替换获得当前日期并用它生成唯一的文件名

today=$(date +%y%m%d)
touch log.$today

输出重定向>
将命令的输出发送到一个文件中:
command > outfile
重定向操作符创建一个test6,并将date命令的输出重定向到该文件中;如果该文件已经存在,>会先把文件清空在输入命令内容
date > test6
如果想将命令的输出追加到已有文件中:>>
who >> test6

输入重定向<
将文件的内容重定向到命令
command < inputfile
记忆方法:在命令行上,命令在左侧文件在右侧,重定向符号“指向”数据流动的方向。

wc < test6
2 11 60
#三个值分别是文本的行数、单词数、字节数

内联输入重定向:<<
你必须指定一个文本标记来划分输入数据的开头和结尾,文本标记必须一致。

format:
command << marker
data
marker

example:
wc << EOF
test string 1
test string 2
test string 3
EOF
 3 9 42

管道:|
将一个命令的输出作为另一个命令的输入。Linux会同时运行两个命令,在系统内部将它们连接起来,在第一个命令产生输出的同时,输出会立即送到第二个命令。
command1 | command2
将命令产生的大量输出通过pipe传送到more,可以强制输出在一屏数据显示后停下来
ls -l | more

执行数学运算
expr命令
expr 1 + 5

expr操作符
arg1 () arg2
arg1 & arg2如果参数非0非NULL,返回arg1;否则返回0
arg1 < arg2True返回1,False返回0
arg1 <= arg2True返回1,False返回0
arg1 = arg2True返回1,False返回0
arg1 != arg2True返回1,False返回0
arg1 >= arg2True返回1,False返回0
arg1 >arg2True返回1,False返回0
arg1 + arg2两数算数运算和
arg1 - arg2两数的算数运算差
arg1 * arg2两数的算数乘积
arg1 / arg2两数的算数商
arg1 % arg2返回余数
string : regexp如果 REGEXP 匹配到了 STRING 中的某个模式,返回该模式匹配
match string regexp如果 REGEXP 匹配到了 STRING 中的某个模式,返回该模式匹配
substr string pos length返回起始位置为pos,长度为length个字符的子字符串(从1开始计数)
index string chars返回在string找到chars字符的为否,找不到返回0
length string返回字符串string的数值长度
#乘法运算时要使用反斜线来转义
expr 5 \* 2

使用方括号
$[ operation ]
使用方括号不用担心shell会误解乘号或其他符号。
bash shell只支持整数运算

var1=100
var2=50
var3=45
var4=$[$var1 * ($var2 - $var3)]

浮点解决方案:bc
在shell提示符下bc命令即可访问bash计算器。bc进入,quit退出。
在这里插入图片描述
在bc里设置计算结果中保留的小数位数
scale=n
在脚本中使用bc:
variable=$(echo "options;expression" | bc)
option设置变量,多个变量用分号分开。
var1=$(echo "scale=4; 3.44 / 5" | bc)
大量运算

variable=$(bc << EOF
options
statements
expressions
EOF
)
var5=$(bc << EOF
scale=4
a1=( $var1 * $car2)
b1=($var3 * $var4)
a1+b1
EOF
)

退出脚本
退出状态码exit status,退出码是一个0-255的整数值
查看状态码echo $?

statuscondition
0命令成功结束
1一般性未知错误
2不适合的shell命令
126命令不可执行
127没找到命令
128无效的退出参数
130Ctrl+c终止的命令
255
128+x与Linux信号x相关的严重错误

exit:允许指定状态码
状态码超过255,会转换为指定的数值除以256后得到的余数

使用if-then语句
以下if-then语句会运行if后面的那个命令,如果该命令的退出码是0(该命令执行成功)
位于then部分的命令就会被执行。

格式1:
if command
then
	commands
fi
格式2:
if command; then
	commands
fi
#一个简单的例子。pwd成功运行退出码为0,then部分的语句会被执行
if pwd
then
	echo "It worked"
fi
#另一个例子。if后接的是错误命令,会产生一个非0的退出码,跳过then部分的语句
if IamNotaCommand
then
	echo "It worked"
fi

在then部分,你可以使用多条命令。

testuser="keiji"
if grep $testuser /etc/passwd
then
	echo "This is my first command"
	echo "This is my second command"
	ls -a /home/$testuser/.b* #列出该用户HOME目录的bash文件
fi

if-then-else语句
当if语句的命令返回退出码0时,then部分的命令会被执行;当命令返回非零退出状态码时,会执行else部分的命令。

if command
then
	commands
else
	commands
fi

完善搜寻用户的例子,用户存在列出其目录下的bash文件;否则告知该用户不存在

testuser="keiji"
if grep $testuser /etc/passwd
then
	echo "The bash file for user $testuser are:"
	ls -a /HOME/$testuser/.b*
else
	echo "The user $testuser does not exist on this system"
fi

嵌套if
要检查/etc/passwd文件是否存在某个用户名以及该用户的目录是否尚在

testuser="keiji"
if grep $testuser /etc/passwd
then
	echo "The user $testuser exists on this system"
else
	echo "The user $testuser does not exist on this system "
	if ls -d /home/$testuser
	then
		echo "However,$testuser has a directory"
	fi
fi

可以使用另一种形式:elif

if command1
then
	commands
elif command2
then
	commands
fi	

改写上一个例子

testuser="keiji"
if grep $testuser /etc/passwd
then
	echo "The user $testuser exists on this system "
elif ls -d /home/$testuser
then
	echo "The user $testuser does not exist on this system"
	echo "However,$testuser has a directory"
else:
	echo "The user $testuser does not exist on this system"
	echo "And,$testuser does not have a directory"
fi	

test命令:测试退出状态码之外的条件
test condition

if test condition
then
	commands
fi

用test命令确定变量中是否有内容

my_variable="full" / my_variable=""
if test $my_variable
then
	echo "The $my_variable expression returns a True"
else
	echo "The $my_variable expression returns a False"
fi

另一种条件测试方法
[ condition]

if [conditon]
then
	commands
fi

数值比较

comparisondescription
n1 -eq n2检查n1是否与n2相等
n1 -gt n2检查n1是否大于n2
n1 -ge n2检查n1是否大于或等于n2
n1 -lt n2检查n1是否小于n2
n1 -le n2检查n1是否小于或等于n2
n1 -ne n2检查n1是否不等于n2

脚本一检查value1是否大于5,脚本2检查value1和value2是否相等

if [ $value1 -gt 5 ] 
if  [ $value1 -eq $value2 ]

字符串比较

comparisondescription
str1 = str2检查str1是否和str2相等
str1 != str2检查str1是否和str2不同
str1 > str2检查str1是都比str2大
str1 < str2检查str1是否比str2小
-z str检查str长度是否为0
-n str检查str长度是否非0

(1)字符串相等性

if [$USER = $testuser ]
if [ $USER != $testuser ]

(2)字符串顺序
大于号和小于号必须转义,否则shell会把它们当做重定向符号。
大于和小于顺序与sort命令所采用的不同。比较测试中使用的是标准的ASCII顺序

if [ $var1 \> $var2 ]
if [$var1 \< $var2 ]

文件比较

comparisondescription
-d file检查file是否存在并是一个目录
-e file检查file是否存在
-f file检查file是否存在并是一个文件
-r file检查file是否存在并可读
-w file检查file是否存在并可写
-x file检查file是否存在并可执行
-s file检查file是否存在并非空
-O file检查file是否存在并属于当前用户
-G file检查file是否存在并属于当前用户群组
file1 -nt file2file1是否比file2新
file1 -ot file2file1是否比file2旧

(1)检查目录
检查目录是否存在于系统中,适用于准备切换到某个目录或将文件写入目录中

if [ -d $jump_directory ]
then
	echo "The $jump_directory exists" 
	cd $jump_directory
	ls
else
	echo "The $jump_directory does not exist"
fi

(2)检查对象

location=$HOME
file_name="sentinel"
if [ -e $location ]
then
	echo "Ok on the $location directory"
	echo "Now checking on the file,$file_name"
 	if [ -e /$location/$file_name ]
 	then
 		echo "Ok on the filename"
 		echo "Updating Current date..."
 		date >> $location/$file_name
 	else
 		echo "File does not exist"
 		echo "Nothing to update"
 	fi
else
	echo "The $location directory does not exist"
	echo "Nothing to update"
fi

(3)检查文件

item_name=$HOME
if [ -e $item_name ]
then 
	echo "The item,$item_name does exist"
	echo "But is it a file?"
	if [ -f $item_name ]
	then
		echo "Yes,$item_name is a file"
	else
		echo "No,$item_name is not a file"
	fi
else
	echo "The item,$item_name does not exist"
fi	

(4)检查是否可读
先用-f检查是否为文件,在用-r检查是否可读
(5)检查空文件
非空文件不删除,空文件删除

if [ -f $file_name ]
then
	if [ -s $file_name ]
	then
		echo "The $file_name file exits and has data"
		echo "Will not remove this file"
	else
		echo "The $file_name file exists,but it is empty"
		rm $file_name
	fi
else
	echo "The $file_name file does not exist"
fi

(6)检查是否可写
if [ -w $item_file ]
(7)检查文件是否可以执行
if [ -x test6.txt ]
(8)检查所属关系、默认属组关系

if [ -O $file_name ]
if [ -G $file_name ]

复合条件测试
第一种布尔运算使用AND来组合两个条件
第二种布尔运算使用OR来组合两个条件

[ condition1] && [condition2]
[ conditoin1] || [ condition2 ]

检查用户的$home目录是否存在,检查其中是否有可写入的testing文件

if [ -d $HOME ] && [ -w $HOME/testing]

使用双括号:数学表达式
shell允许你在条件中使用高级数学表达式
(( expression ))

signaldescription
val++后增
val–后减
++val先增
–val先减
!逻辑求反
~位求反
**幂运算
<<左位移
>>右位移
&位布尔和
()
&&逻辑和
(

if (( $val1 ** 2 > 90 ))

使用双方括号
双方括号提供了模式匹配(pattern matching)
[[ expression ]]
if [[ $USER == r* ]]

case命令

case $variable in 
pattern1 | pattern2)
	commands;;
pattern3)
	commands;;
*)
	commands;;
esac

for命令
重复执行一系列命令

for var in list
do
	commands
done

读取列表中的值

for test in Alabama Alaska Arizona Arkansas 
do
	echo The next state is $test
done
echo "The last atate we visited was $test" #变量会一直保持最后一次迭代的值,除非你修改它

读取列表中的复杂值
两种办法:使用转义符来将单引号转义
使用双引号来定义用单引号的值

for test in I don\'t know if "this'll" work
do
	echo "word:$test"
done

对于包含空格的数值,必须用双引号将他们圈起来。因为for命令用空格来划分列表中的每个值。

for test in Nevada "New Hampshire" "New Mexico" "New York"
do
	echo "Now going to $test"
done

从变量读取列表

#将一个列表放在变量里
list="Alabama Alaska Arizona Arkansas Colorado"
#向$list变量包含的已有列表中添加一个值
list=$list" Connecticut"
for state in $list
do
	echo "Now go to $state"
done

从命令读取值
for state in $(cat $file)
更改字段的分割符
IFS(internal field separator):内部字段分隔符
默认情况下,shell会将 空格、制表符和换行符当做字段分隔符。这在处理含有空格的数据时,非常麻烦。
想修改IFS的值使其只能识别换行符,忽略空格和制表符:
IFS=$'\n'
修改IFS值之前要保存原来的IFS值

IFS_OLD=$IFS
IFS=$'\n'
IFS=$IFS_OLD

将IFS的值设为冒号
IFS=:
指定多个IFS字符
IFS=$'\n':;"

用通配符读取目录
循环处理某目录下的所有文件
for file in /home/rich/test*
因为文件名之间可能有空格,在判断文件类型时需要把文件名用双引号圈起来
if [ -f "$file" ]

C语言风格的for命令
for (( variable assignment; condition; iteration process ))
变量赋值可以用空格
条件中的变量不以$开头
迭代过程的算式未用expr命令格式
在这里插入图片描述
使用多个变量

for (( a=1,b=10; a<=10;a++,b--))
do
	echo "$a-$b"
done

while命令
只要测试条件成立,命令就会不停地循环

while [condition]
do
	commands
done

打印10-0

var1=10
while [ $var1 -gt 0 ]
do
	echo $var1
	var1=$[ $var1 -1 ]
done

使用多个测试命令
在while语句定义多个测试命令,只有最后一个测试命令的退出状态码能决定何时停止循环
在这里插入图片描述
until命令
只有测试条件成立时,循坏才会结束

until [ condition ]
do
	commands
done

嵌套循环
在这里插入图片描述

for (( a=1;a<=2;a++ ))
do 
	echo "Starting loop $a:"
	for (( b=1;b<=3;b++ ))
	do
		echo "Inside loop:$b"
	done
done

在这里插入图片描述

var1=5
while [ $var1 -ge 0]
do
	echo "Outside loop:$var1"
	for (( var2=1;var2<3;var2++))
	do
		var3=$[ $var1*$var2]
		echo"   Inner loop:$var1 * $var2 = $var3 "
	done
	var1=$[ $var1 -1 ]
done

循环处理文件数据
在这里插入图片描述

IFS_OLD=$IFS
$IFS=$'\n'
for entry in $(cat /etc/passwd)
do
	echo "Values in $entry"
	$IFS=:
	for field in $entry:
	do
		echo $field
	done
done

控制循环:break命令
(1)跳出单个循环

for var1 in 1 2 3 4 5 6 7 8 9 10
do
	if [ $var1 -eq 5 ]
	then
		break #var1等于5就跳出该循环
	fi
	echo "Iteration number:$var1"
done

while [ $var1 -lt 10 ]
do
	if [ $var1 -eq 5 ]
	then
		break
	fi
	echo "Itreration:$var1"
	var1=$[ $var1 +1 ]
done

(2)跳出内部循环
处理多个循环时,break命令会自动终止你所在的最内层的循环
在这里插入图片描述

for ((a=1;a<4;a++))
do
	echo "Outer loop:$a"
	for ((b=1;b<100;b++))  #跳出这个循环
	do
		if [ $b -eq 5 ]
		then
			break
		fi
	    echo " Inner loop:$b"
	done
done

(3)跳出外部循环
n指定要跳出的循环层数,默认n=1;n=1表明要跳出当前循环,n=2停止下一级的外部循环
break n

Continue命令
continue会跳过剩余的命令,但不会跳出整个循环。
在这里插入图片描述

for (( var1=1 ; var1 < 15; var1++))
do
	if [ $var1 -gt 5 ] && [ $var1 -lt 10 ]
	then
		continue
	fi
	echo "Iteration number:$var1"
done

处理循环的输出
将for命令的结果重定向到文件,而不是显示在屏幕上
done > output.txt
改变输出结果的顺序done | sort

查找可执行文件

IFS=:
for folder in $PATH
do
	echo "$folder:"
	for file in $folder/*
	do 
		if [ -x $file ]
		then
			echo "  $file"
	 	fi
	done
done

创建多个用户账号
有一个文本文件的格式是:userid,user name
读取该文件各行
while IFS=',' read -r userid name

input="users.csv"
while IFS=',' read -r userid name
do
	echo "adding $userid"
	useradd -c "$name" -m $usrid
done < "$input"

处理用户输入
命令行参数:
向脚本addem 传递两个命令参数10和30
./addem 10 30
读取参数
$0是程序名,$1是第一个参数以此类推

factorial=1
for (( number=1 ; number<=$1 ; number++))
do
	factorial=$[ $factorial * $number]
done
echo "The factorial of $1 is $factotial"

运行
./test1.sh 5

如果输入多个命令行参数,要用空格隔开;包含空格的参数要用引号圈起来

total=$[ $1 *$2 ]
echo "The first parameter is $1"
echo "The second parameter is $2"
echo The total value is $total

运行
./test2.sh 2 5

echo Hello $1,glad to meet you

运行
./test3.sh "Rich Blum"
如果脚本需要的命令行参数不止9个,在第9个后的变量,要在数字周围加上花括号
${10}

读取脚本名
用$0参数获取shell在命令行启动的脚本名

name=$( basename $0)
echo The script name is $name

执行不同功能的脚本,脚本名是addem就将两个参数相加;脚本名是multem就将两个脚本相乘

name=$[ basename $0 ]
if [ $name = "addem" ]
then
	total=$[ $1 + $2 ]
elif [ $name = "multem" ] 
then
	total=$[ $1 * $2 ]
fi
echo "The calculated value is $total" 

测试参数
检查是否存在参数
if [ -n "$1" ]

特殊参数变量
参数统计$#
判断参数总数是否为2,是将两个参数相加,不是提示用户

if [ $# -ne 2 ]
then
	echo
	echo Useage:test9.sh a b
	echo
else
	total=$[ $1 +$2 ]
	echo The total is $total
fi

最后一个参数变量${!#}
当命令行没有参数时,$#的值为0,但 ${ $#}变量会返回脚本名

抓取所有的数据

"$*" 会将命令行所有的参数当做一个单词
"$@" 会将命令行上提供的所有参数当做同一个字符串上的多个独立单词 (可以用for循环逐个获取参数)

移动变量:shift
shift:默认将每个参数向左移动一个位置,最后$1的值会被删除
在不知道参数数量情况下,遍历参数

count=1
while [ -n "$1"]
do
	echo "Parameter #$count = $1 "
	count=$[ $count +1 ]
	shift
done

可以用shift n来指明要移动的位置数。

获得用户输入:read
read -p 允许直接在read命令行指定提示符

read -p "Please enter your age:" age
days=$[ $age * 365 ]
echo "That makes you over $days days old"

read -p 可以指定多个变量:

read -p "Enter your name:" first last
echo "Checking data for $last $first"

read -t可以指定命令等待的秒数,如果计数器过期,read命令会返回非0退出码
read -t 5 -p "Please enter your name" name
read -n 统计输入的字符数,当输入的字符达到预设的字符数就会自动退出
read -n 1 -p "Do you want to continue [Y/N]?" answer
read -s 隐藏方式读取,避免read命令输入的数据出现在显示器上
read -s -p "Enter your passwd" pass
从文件中读取,用read命令读取文本,每次它都会从文件中读取每一行文本。当文件中再没有内容。

count=1
cat test | while read line
do
	echo "Line $count: $line"
	count=$[ $count +1 ]
done
echo "Finished processing the file"

理解输入和输出
在显示器屏幕上显示输出
将输出重定向到文件上

标准文件描述符

文件描述符、缩写描述
0、STDIN标准输入
1、STDOUT标准输出
2、STDERR标准错误

STDIN:文件描述符shell的标准输入。对终端界面来说,标准输入是键盘。shell从STDIN文件标准符对应的键盘获得输入,在用户输入时处理每个字符。输入重定向符号(<)时,Linux会用重定向指定的文件。

cat<marker
data
marker

cat<<EOF>file
data
EOF

STDOUT:代表shell的标准输出。
命令的结果输出到test2文件
ls -l > test2
(>>)将数据追加到某个文件
who >> test2

STDERR:shell文件描述符来处理错误消息
(1)只重定向错误2>file错误消息不会出现在屏幕上了。该命令生成的任何错误消息都会保存在输出文件中。
ls -al badfile 2>test4
(2)重定向错误和数据
必须用两个重定向符号,正确输出重定向到test7;错误消息重定向到test6
ls -al test test2 test3 badtest 2>test6 1>test7
(3)将STDERR和STDOUT的输出重定向到一个输出文件 &>
ls -al test test2 test3 badtest &> test7

临时重定向
有意在脚本中生成错误信息:>&2
echo "This is an error message" >&2
如何运行脚本使临时重定向生效?错误信息会存到test9中
./test8 2> test9

永久重定向
exec命令:exec 1>testout exec 2>testerr
告诉shell在脚本执行期间重定向某个特定文件描述符

在脚本中重定向输入
exec 0 < filename
exec命令可以将STDIN重定向到Linux系统上的文件

exec 0< testfile
count=1
while read line
do
	echo "Line #$count:$line"
	count=$[ $count +1 ]
done

创建输出文件描述符

exec 3>filename
echo string >& 3
exec 3>>filename #输出追加到现有的文件中

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值