先介绍一下什么是shell吧:
壳层在计算机科学中,是指“提供用户使用界面”的软件,通常指的是命令行界面的解析器。一般来说,这
个词是指操作系统中,提供访问内核所提供之服务的程序。Shell也用于泛指所有为用户提供操作界面的
程序,也就是程序和用户交互的层面。因此与之相对的是程序内核,内核不提供和用户的交互功能。 不
过这个词也拿来指应用软件,或是任何在特定组件外围的软件,例如浏览器或电子邮件软件是HTML排版
引擎的shell。Shell这个词是来自于操作系统与用户界面的外层界面。 通常将壳层分为两类:命令行与图
形界面。命令行壳层提供一个命令行界面;而图形壳层提供一个图形用户界面。
bash:据我老师说的,第一次能把Hello world程序成功运行出来,你将会在学习的路上会顺利一点,嘿嘿,有点小迷信了,那么就先从Hello world程序开始吧。
用vim编辑器编辑hello文件:
#!/bin/bash
# This is a simple example
echp Hello world
这时候该有同学问#!是什么啊,有什么用,/bin/bash又是什么,
首先,#! 是说明 hello 这个文件的类型的,有点类似于 Windows 系统下用不同文件后缀来表示不同文件类型的意思(但不相同)。Linux 系统根据 “#!” 及该字串后面的信息确定该文件的类型。
其次,在 BASH 中 第一行的 “#!” 及后面的 “/bin/bash” 就表明该文件是一个 BASH 程序,需要由 /bin 目录下的 bash 程序来解释执行。BASH 这个程序一般是存放在 /bin 目录下,如果你的 Linux 系统比较特别,bash 也有可能被存放在 /sbin 、/usr/local/bin 、/usr/bin 、/usr/sbin 或 /usr/local/sbin 这样的目录下。
如何执行该程序呢?有两种方法:一种是显式制定 BASH 去执行:
$ bash hello 或
$ sh hello (这里 sh 是指向 bash 的一个链接,“lrwxrwxrwx 1 root root 4 Aug 20 05:41 /bin/sh -> bash”)
或者可以先将 hello 文件改为可以执行的文件,然后直接运行它,此时由于 hello 文件第一行的 “#! /bin/bash” 的作用,系统会自动用/bin/bash 程序去解释执行 hello 文件的:
$ chmod u+x hello
$ ./hello
此处没有直接 “$ hello”是因为当前目录不是当前用户可执行文件的默认目录,而将当前目录“.”设为默认目录是一个不安全的设置。
需要注意的是,BASH 程序被执行后,实际上 Linux 系统是另外开设了一个进程来运行的。
bash特性之命令别名和命令引用
alias
alias ALIAS=COMMAND
示例:
[root@stu31 ~]# alias ls='ls -la'
[root@stu31 ~]# ls /tmp/
total 80
drwxrwxrwt. 5 root root 4096 Aug 3 12:19 .
dr-xr-xr-x. 27 root root 4096 Aug 3 11:12 ..
drwxr-xr-x 2 root root 4096 Jul 28 14:58 dangerous
-rw------- 1 root root 0 Jul 28 10:04 grub-install.img.504t6u
-rw------- 1 root root 401 Jul 28 10:04 grub-install.log.fPXD9g
drwxrwxrwt 2 root root 4096 Aug 3 11:12 .ICE-unix
-rwx------. 1 root root 1118 Jul 28 09:11 ks-script-0C1VlZ
-rwxr-xr-x. 1 root root 67 Jul 28 09:11 ks-script-0C1VlZ.log
drwxr-xr-x 2 root root 53248 Jul 28 14:48 test
-rw-------. 1 root root 0 Jul 28 08:47 yum.log
别名与命令同名时,要使用绝对路径,\COMMAND生效范围:命令行定义的别名,其生效范围为当前会话;
unalias [ALIAS]
-a: 撤消所有别名
示例:
[root@stu31 ~]# unalias ls
[root@stu31 ~]# ls /tmp/
dangerous grub-install.log.fPXD9g ks-script-0C1VlZ.logyum.log
grub-install.img.504t6u ks-script-0C1VlZ test
bash支持的引用:
''
""
``:引用一个命令的执行结果
示例:
1alias ls='ls --color=auto' #输出显示为彩色
2[root@stu31 /]# cd `who am i`
[root@stu31 ~]#
bash特性之文件名通配(globbing):
?:匹配任意字符
*:匹配任意长度任意字符
例:*a *b a*b *a*b*
[]:匹配指定范围内的任意单字符
例:[a-z];[0-9];[a-z0-9]
[^]:匹配指定范围意外的任意单字符
例:[^0-9]
字符集合:
[:space:] : 所有空白字符
[:punct:] : 所有标点符号
[:lower:] :所有小写字母
[:upper:] :所有大写字母
[:digit:] :所有数字
[:alnum:] :所有大小写字母和数字
[:alpha:] :所有字母
示例:显示/etc目录下,以非字母开头,文件或目录;
# ls -d /etc/[^[:alpha:]]*
bash之快捷键:
Ctrl+a: 跳转至命令行首
Ctrl+e: 跳转至命令行尾
Ctrl+u: 删除命令行首至当前光标所在处之前的所有内容
Ctrl+k: 删除当前光标所在处至命令行尾的所有内容
Ctrl+l: 清屏
Ctrl+c: 中止或取消
Ctrl+z: 把当命令送至后台
bash之bash变量:
bash变量类别:
本地变量:只对当前shell进程有效的变量;对其它shell进程无效,包当前 shell进程的子进程;
VAR_NAME=VALUE
变量赋值:向变量的存储空间保存数据
示例:
[root@stu31 ~]# a=1
[root@stu31 ~]# b=2
[root@stu31 ~]# echo $a
1
[root@stu31 ~]# echo $b
2
变量引用:${VAR_NAME}
"":弱引用,里面的变量会被替换;
'':强引用,里面的所有字符都是字面量,直接输出;
环境变量:对当前shell进程及其子shell有效,对其它的shell进程无效;
定义:export VAR_NAME=VALUE
导出:export VAR_NAME
用户可自义环境变量
bash有许多内置的环境变量
撤消变量:unset VAR_NAME
只读变量:readonly VAR_NAME
局部变量:
对shell脚本中某代码片断有效;通常用于函数本地;
local VAR_NAME=VALUE
位置变量:
$1, $2, ..., ${10}
查看当前shell进程中的所有变量:set
查看当前shell进程中的所有环境变量:export, printenv, env
变量命名:
1、不能使用程序中的关键字(保留字);
比如:if, case, for
2、只能使用数字、字母和下划线,且不能以数字开头;
3、要见名知义
File
变量类型:
name=Jerry
1、存储机制
2、存储空间
3、参与的运算方式
变量类型:
数值型:
精确数值:整数
近似数值:浮点型
单精度浮点
双精度浮点
字符型:
char
string
布尔型:
true, false
类型转换:
显式转换
隐式转换
bash是弱类型的语言:一切皆字符
bash之bash的配置文件:
profile类:为交互式登录的用户提供配置
全局:
/etc/profile
/etc/profile.d/*.sh
用户:
~/.bash_profile
功用:
1、设定环境变量
2、运行命令或脚本
bashrc类:为非交互式的用户提供配置
全局:
/etc/bashrc
用户:
~/.bashrc
功用:
1、设定本地变量
2、定义命令别名
登录类型:
交互式:
直接通过终端输入账号和密码登录;
使用su -l USERNAME 或 su - USERNAME;
非交互式:
su USERNAME
图形界面下打开的终端
执行脚本
通过编辑配置文件修改的配置生效?
1、退出并重新登录;
2、让bash重读此配置文件;
. FILE
source FILE
交互登录的用户:
/etc/profile --> /etc/profile.d/*.sh --> ~/.bash_profile --> ~/.bashrc --> /etc/bashrc
非交互登录的用户:
~/.bashrc --> /etc/bashrc --> /etc/profile.d/*.sh
bash之bash编程:
特殊变量:
$#,$*: 传递给脚本参数的个数
$@:引用传递给脚本的所有参数
$?:状态返回值
bash的循环语句:
for
while
until
for语句格式:
for 变量 in 列表 ;do
执行的命令
done
(退出条件:遍历结束)
for的第二种使用格式 :
for ((初始条件;测试条件;修改表达式)); do
循环体
done
例:for file in `ls`;do echo $file;done
创建十个文件夹file1-file10
#!/bin/bash
for fileName in {1..10};do
touch file$(fileName)
done
计算100以内所有正整数之和
#!/bin/bash
#
declare -i sum=0
for ((counter=1;$counter <= 100; counter++)); do
let sum+=$counter
done
echo $sum
while语句格式:
while 条件; (注:只要特定条件为真,”while” 语句就会执行)
do
语句
done
示例:
#!/bin/bash
COUNTER=0
while [ $COUNTER -lt 10 ]; do
echo The counter is $COUNTER
let COUNTER=COUNTER+1
done
until语句格式:
until 条件; (注:只要特定条件为假,”while” 语句就会执行)
do
语句
done
示例:
#!/bin/bash
myvar=1
until [ $myvar -gt 10 ]do
echo $myvar
myvar=$(( $myvar + 1 ))
done
生成列表的方式:
1、手动给个列表:
for i in 1 2 3 4 5;
2、数值列表:
{start..end}
`seq [start [increment]] end`
3、$*, $@
4 、命令生成列表
示例:
显示/etc/passwd文件中位于文件的第偶数行的用户名;并显示共有多少个这样的用户;
#!/bin/bash
#
totalUsers=`wc -l /etc/passwd | cut -d' ' -f1`
for i in `seq 2 2 $totalUsers`; do
userName=`head -n $i /etc/passwd | tail -1 | cut -d: -f1`
echo $userName >> /tmp/passwd.tmp
echo $userName
done
users=`wc -l /tmp/passwd.tmp | cut -d' ' -f1`
echo "Total users: $users."
bash之bash如何实现算术运算:
变量:弱类型
如何定义整型变量:
let VAR_NAME=INTEGER_VALUE
例如:let a=1
declare -i VAR_NAME=INTEGER_VALUE
例如:declare -i a=3
注意:即使没有定义为整型变量,字符型的数字依然可以参与算术运算;bash会执行变量类型的隐式类型转换;
实现算术运算的方式:
let VAR_NAME=ARITHMATIC_EXPRESSION
VAR_NAME=$[ARITHMATIC_EXRESSION]
VAR_NAME=$((EXPRESSION))
VAR_NAME=$(expr $num1 + $num2)
算术运算符:
+
-
*
/
%:取模,取余数
5%2=1,
**: 2**3 (这是次方运算,2的3次方)
示例:
分别计算100以内所有偶数之和和奇数之和;
#!/bin/bash
#
declare -i evensum=0
declare -i oddsum=0
for i in `seq 1 2 100`; do
oddsum=$[$oddsum+$i]
done
for j in `seq 2 2 100`; do
evensum=$[$evensum+$j]
done
echo "evensum: $evensum, oddsum: $oddsum."
写一个脚本
1、脚本可以接受一个以上的文件路径作为参数;
2、显示每个文件所拥有的行数;
3、显示本次共对多少个文件执行了行数统计;
4、显示所有文件的总行数;
#!/bin/bash
#
declare -i totalLines=0
declare -i noFiles=0
for file in $*; do
curFileLines=`wc -l $file | cut -d' ' -f1`
echo "$file has $curFileLines."
let noFiles++
let totalLines+=$curFileLines
done
echo "Total Files: $noFiles."
echo "Total Lines: $totalLines."
bash弱类型:
变量=值
任何无需事先声明,可直接使用
值默认都是字符型
a=abc, b=3
a=3
赋值:
a=4
增强型赋值:
+=, -=, *=, /=, %=
a=$[$a+1] 相当于 let a+=1
自加:var++, var--, ++var, --var
export PATH=$PATH:/usr/local/apache/bin
unset: 撤消
算术运算:bash会对数字执行隐式的类型转换
let VAR_NAME=Integer_Value
declare -i Var_Name=Integer_Value
操作符:
+, -, *, /, %, **
双目运算符:需要至少两个操作数
bash的算术运算的方式:
let Var_Name=EXPRESSION
$[EXPRESSION]
$((EXPRESSION))
命令:expr ARG1 OP ARG2
例:计算100内的所有正整数的和
#!/bin/bash
declare -i sum=0
for i in {1..100}; do
let sum+=$i
done
echo $sum
逻辑运算:
布尔运算:真,假
与、或、非、异或
与运算:
真,假:
真 && 真 = 真
真 && 假 = 假
假 && 真 = 假
假 && 假 = 假
或运算:
真,假
真 || 真 = 真
真 || 假 = 真
假 || 真 = 真
假 || 假 = 假
非运算:
真,假
!真=假
!假=真
命令都有其状态返回值:
成功:0,真
失败:1-255, 假
bash条件测试:
命令执行成功与否即为条件测试
test EXPR
[ EXPR ]
[[ EXPR ]]
比较运算:
>, <, >=, <=, ==, !=
测试类型:根据比较时的操作数的类型
整型测试:整数比较
字符测试:字符串比较
文件测试:判断文件的存在性及属性等
(注意:比较运算通常只在同一种类型间进行)
整型测试:
-gt: 大于
-lt: 小于
-ge: 大于等于
-le: 小于等于
-eq: 等于
-ne: 不等于
字符串测试:
双目
>: [[ "$string1" > "$string2" ]]
<:
>=
<=
==
!=
单目:
-n String: 是否不空,不空则为真,空则为假
-z String: 是否为空,空则为真,不空则假
bash之bash选择:
if: 三种使用格式
单分支的if语句:
if 测试条件; then
选择分支
fi
表示条件测试状态返回值为值,则执行选择分支;
双分支的if语句:
if 测试条件; then
选择分支1
else
选择分支2
fi
两个分支仅执行其中之一。
多分支的if语句:
if 条件1; then
分支1
elif 条件2; then
分支2
elif 条件3; then
分支3
...
else
分支n
fi
例:1写一个脚本,接受一个参数,这个参数是用户名;如果此用户存在,则显示其ID号;
#!/bin/bash
if ! id $username &> /dev/null; then
useradd $username
fi
2通过命令行给定一个文件路径,而后判断:
如果此文件中存在空白行,则显示其空白行的总数;
否则,则显示无空白行;
#!/bin/bash
if grep "^[[:space]]*$" $1 &> /dev/null; then
echo "$1 has $(grep "^[[:space]]*$" $1 | wc -l) blank lines."
else
echo "No blank lines"
fi
3传递一个用户名给脚本:
如果此用户的id号为0,则显示说这是管理员
如果此用户的id号大于等于500,则显示说这是普通用户
否则,则说这是系统用户;
#!/bin/bash
if [ $# -lt 1 ]; then
echo "Usage: `basename $0` username"
exit 1
fi
if ! id -u $1 &> /dev/null; then
echo "Usage: `basename $0` username"
echo "No this user $1."
exit 2
fi
if [ $(id -u $1) -eq 0 ]; then
echo "Admin"
elif [ $(id -u $1) -ge 500 ]; then
echo "Common user."
else
echo "System user."
fi
bash字串测试中的模式匹配:
[[ "$var" =~ PATTERN ]]
例:让用户给定一个用户名,判断其是否拥有可登录shell;
#!/bin/bash
#
read -p "Plz input a username: " userName
userInfo=`grep "^$userName\>" /etc/passwd`
if [[ "$userInfo" =~ /bin/.*sh$ ]]; then
echo "can login"
else
echo "cannot login"
fi
bash之case语句:
一般,case语句和if一起使用,但是只要你面临可能采取的一系列不同的动作时,你可能迷惑,要处理复杂条件时,你可以考虑一下case语句
case表达式:
case
EXPRESSION
in
CASE1
) COMMAND-LIST;;
CASE2
) COMMAND-LIST;;
...
COMMAND-LIST;; CASEN
)
esac
每个分支是一个符合pattern的表达式,在COMMAND-LIST中首先符合的命令就执行该条,没个case语句以esac结束
例:
#!/bin/bash
# 1.) Open file 2.) Display file 3.) Edit file 4.) Delete file
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
echo "---------------------------------"
echo "List of item to operate file -"
echo "---------------------------------"
echo "1). Open a file -"
echo "2). Display a file -"
echo "3). Edit a file -"
echo "4). Delete a file -"
echo "---------------------------------"
read select
case $select in
1)
echo "do open file operation"
2)
echo "do display a file operation"
3)
echo "do edit a file operation"
4)
echo "do delete a file operation"
*)
echo "There is nothing to do!"
exit 1
esac
bash之数组:
1,声明一个数组
declare -i array
2,数组赋值
(1) array=(a1 a2 a3 ... aN)
(2)array=([0]=a1 [2]=a2 [3]=a3 ... [n]=aN)
(3)array[0]=a1 array[1]=a2 array[2]=a3 ... array[n]=aN
3,数组复制:
要使用${ARRAY[@]}
$@: 每个参数是一个独立的串
$*: 所有参数是一个串
4,引用数组
echo ${array[n]}
5,数组的访问:
用索引访问:
ARRAY[index]
6,从数组中挑选某元素:
${ARRAY[@]:offset:number}
切片:
offset: 偏移的元素个数
number: 取出的元素的个数
${ARRAY[@]:offset}:取出偏移量后的所有元素
${ARRAY[@]}: 取出所有元素
7,从数组中删除元素:
unset ARRAY[index]
例:将字串里的字母逐个放入数组中并输出
#!/bin/bah
chars='qazwsx'
for((i=0;i<=6;i++));do
array[$i]=${chars:$i:1} (表示从chars字符串的 $i 位置开始,获取 1 个字符)
echo ${array$[$i]}
done
复制一个数组中下标为偶数的元素至一个新数组中
#!/bin/bash
declare -a mylogs
logs=(/var/log/*.log)
echo ${logs[@]}
for i in `seq 0 ${#logs[@]}`; do
if [ $[$i%2] -eq 0 ];then
index=${#mylogs[@]}
mylogs[$index]=${logs[$i]}
fi
done
echo ${mylogs[@]}
祝大家看的愉快
本文出自 “Linux” 博客,转载请与作者联系!