Unix基础之环境变量
前言:
第一招 HelloWorld:
echo -n # 不带换行
devzkndeMacBook-Pro:~ devzkn$ echo -n hello kevin
hello kevindevzkndeMacBook-Pro:~ devzkn$
第二招 判断:
第一式:if
-
if true
-
then
-
echo "Hello World"
-
else
-
echo "Bug"
-
fi
-
-
if false
-
then
-
echo "Hello World"
-
elif true
-
then
-
echo "Bug"
-
else
-
echo "Bee"
-
fi
判断原理
if
、elif
会执行它后面跟着的命令,然后看返回值是否为0
,如果为0
则执行then
下面的语句块,否则执行else
下面的语句块。
devzkndeMacBook-Pro:~ devzkn$ true
devzkndeMacBook-Pro:~ devzkn$ echo $?
0
devzkndeMacBook-Pro:~ devzkn$ false
devzkndeMacBook-Pro:~ devzkn$ echo $?
1
devzkndeMacBook-Pro:~ devzkn$
true
、false
事实上也为一个命令,true
的返回码必为0
,false
的返回码必为1
$?
为shell
内置变量,用于存放上一个命令的返回码
第二式:test、[ ] 和 [[ ]]
test
、[ ]
、[[ ]]
实际上都是shell
中的命令,执行之后会返回1
或0
,而这几个命令与if
相结合可以达到我们所需要的许多判断功能,例如测试字符串是否为空的三种写法
-
s=""
-
if [ -z ${s} ]
-
then
-
echo "empty"
-
fi
-
-
if [[ -z ${s} ]]
-
then
-
echo "empty"
-
fi
-
-
if test -z ${s}
-
then
-
echo "empty"
-
fi
devzkndeMacBook-Pro:test devzkn$ cat test.sh
s=$1;
if test -z ${s}
then
echo "empty"
fi
devzkndeMacBook-Pro:test devzkn$ sh -x test.sh
+ s=
+ test -z
+ echo empty
empty
devzkndeMacBook-Pro:test devzkn$ sh -x test.sh s
+ s=s
+ test -z s
devzkndeMacBook-Pro:test devzkn$
[ ]
和 test
性能基本相同, [[ ]]
性能是最高的,为前两者的 5
倍左右(以 -d
运算符测试),所以建议尽量使用 [[ ]]
提高脚本性能。
[ ]
中使用 <
和 >
,需要将它们写成 \<
和 \>
&&
可以用来对两个判断语句求与;注:只有[[ ]]
才允许把&&,||
写在里面小技巧
&&
、||
还可以用来拼接命令,达到按前一个命令成功与否来决定是否执行后一个命令的效果
-
cd /data && ls # 当`cd /data`返回0(即成功)时才执行后面的`ls`
-
cd /data || cd /root # 当`cd /data`返回非0(即失败)时才执行后面的`cd /root`
devzkndeMacBook-Pro:test devzkn$ cd ../ &&ls
Desktop Library Pictures mydoc
Documents Movies Public test
Downloads Music demand
devzkndeMacBook-Pro:~ devzkn$ cd test1 || cd test
-bash: cd: test1: No such file or directory
devzkndeMacBook-Pro:test devzkn$
第一式:for
第一式:for
-
for i in {1..100}
-
do
-
echo ${i}
-
done
注:
{1..100}
属于通配的一种写法,展开会是1 2 3 ... 100
(1~100以空格隔开)这样的字串。例如
for i in 1 2 3;
这样的语句,for
会将1
、2
、3
依次赋值于i
进行循环,而对于通配的情况,for
则会将通配展开后将里面的每一项依次赋值于i
进行循环。示例1:
devzkndeMacBook-Pro:test devzkn$ cat test_for.sh
for i in {1..11}
do
echo ${i}
done
devzkndeMacBook-Pro:test devzkn$ sh test_for.sh
1
2
3
4
5
6
7
8
9
10
11
ps: 1..$1 就不可以达到通配的效果
示例2:
cd ~/trc/$1 for webxxx in `cat ~/kevin/$2` do # zmore $webxxx |awk -f ~/kevin/rmline.awk| grep xxxx.action |grep -E " [0-9]+\** " | awk -F '[' '{print $2,$4,$6}'|sed 's/];发送://'|sed 's/]//' #more $webxxx |awk -f ~/kevin/rmline.awk| grep xxxx.action |grep -E " [0-9]+\** " | awk -F '[' '{print $2,$4,$6}'|sed 's/];发送://'|sed 's/]//' #more $webxxx |awk -f ~/kevin/rmline.awk| grep 2201194.d |grep -E " [0-9]+\** " | awk -F '[' '{print $2,$4,$6}'|sed 's/];发送://'|sed 's/]//' more $webxxx |awk -f ~/kevin/rmline.awk| grep xxx.d |grep -E " [0-9]+\** " | awk -F '[' '{print $2,$4,$6}'|sed 's/];发送://'|sed 's/]//' done
反引号(`)之间的命令会被执行,其输出结果会转换成一个变量
ps: 可使用seq 序列命令seq -- print sequences of numbers
devzkndeMacBook-Pro:test devzkn$ cat test_for.sh
for i in `seq 1 3 20`
do
echo ${i}
done
devzkndeMacBook-Pro:test devzkn$ sh test_for.sh
1
4
7
10
13
16
19
for ((i = 0; i < 100; i++)) do echo ${i} done for ((i = 0; i < 100; i+= 2)) do echo ${i} done注:
以上与C语言式的
for
循环语法基本相同,区别在于双重括号:(( ))
i=0 while [[ ${i} -lt 100 ]] do echo ${i} ((i++)) done
i=0 until [[ ${i} -ge 100 ]] do echo ${i} ((i++)) done注:
while
和until
的判断原理与if
是类似的,它会执行并它后面跟着的命令,不同点在于:
while
是后面语句返回值为0
,则执行循环中的语句块,否则跳出循环;until
则是后面语句返回值非0
,则执行循环中的语句块,否则跳出循环。
第四招:变量
第一式:整数
整数的运算
方法较多,此处只列举最浅显易懂,并且效率最高的办法——直接将符合C语言语法的表达式放到
(( ))
中即可达到对整数的计算目的:
echo $(( 1+1 )) # 最简单的1+1 echo $(( (1+2)*3/4 )) # 表达式中还可以带括号 echo $(( 1<<32 )) # 左移右移也支持,但仅限于-4294967296~4294967296之间的数值 echo $(( 1&3 )) # &、^、|、~ 这样的位操作亦支持 (( i=1+2 )) # 将1+2计算出结果后赋值给i,后续若`echo ${i}`会得到3 (( i++ )) # 变量i自增1 (( i+=3 )) # 变量i自增3 # ... # 还有很多,不再详列注:
进行整数运算的方法还有:
expr
、$[]
、let
等shell
等内置命令,也可调用bc
、python
等外部工具进行更复杂的数学运算
第二式:字符串
替换
操作 含义 ${string/old/new} string中第一个old替换为new ${string//old/new} string中所有old替换为new
devzkndeMacBook-Pro:test devzkn$ s="i hate hate kevin\!"
devzkndeMacBook-Pro:test devzkn$ echo $s
i hate hate kevin\!
devzkndeMacBook-Pro:test devzkn$ echo ${s/hate/love}
i love hate kevin\!
devzkndeMacBook-Pro:test devzkn$ s="i hate hate kevin"
devzkndeMacBook-Pro:test devzkn$ echo ${s//hate/love}
i love love kevin
截取子串
操作 | 含义 |
---|---|
${string:n} | string从下标n到结尾的子串 |
${string:n:m} | string从下标n开始长度为m的子串 |
${string::m} | string从下标0开始长度为m的子串 |
通配删除
通配删除,即按通配符,删除掉字符串中符合条件的一部分
操作 | 含义 |
---|---|
${string#pattern} | string从左到右删除pattern的最小通配 |
${string##pattern} | string从左到右删除pattern的最大通配 |
${string%pattern} | string从右到左删除pattern的最小通配 |
${string%%pattern} | string从右到左删除pattern的最大通配 |
注:
- 此处通配规则参考通配符一览表
- 最小通配和最大通配的区别: 最小通配:符合通配的最小子串 最大通配:符合通配的最大子串 例如string值为
/00/01/02/dir
,对于通配/*/
,其最小通配为/00/
,而最大通配/00/01/02/
小技巧
- 获取文件名:
${path##*/}
(相当于basename
命令的功能) - 获取目录名:
${path%/*}
(相当于dirname
命令的功能) - 获取后缀名:
${path##*.}
devzkndeMacBook-Pro:test devzkn$ s="/Users/devzkn/test.sh"
devzkndeMacBook-Pro:test devzkn$ echo ${s##*/}
test.sh
devzkndeMacBook-Pro:test devzkn$ echo ${s%/*}
/Users/devzkn
devzkndeMacBook-Pro:test devzkn$ echo ${s##*.}
sh
第三式:数组
普通数组
-
a=() # 空数组
-
a=(1 2 3) # 元素为1,2,3的数组
-
echo ${#a[*]} # 数组长度
-
echo ${a[2]} # 下标为2的元素值(下标从0开始)
-
a[1]=0 # 给下标为1的元素赋值
-
-
# 遍历数组
-
for i in ${a[*]}
-
do
-
echo ${i}
-
done
-
-
unset a # 清空数组
关联数组
关联数组可以用于存储key-value
型的数据,其功能相当于C++
中的map
或python
中的dict
。
-
declare -A a # 声明关联数组(必须有此句)
-
a=(["apple"]="a1" ["banana"]="b2" ["carrot"]="c3") # 初始化关联数组
-
echo ${#a[*]} # 获取元素个数
-
echo ${a["carrot"]} # 获取元素值
-
a["durian"]="d4" # 插入或修改元素
-
echo ${!a[*]} # 获取所有的key
-
unset a["banana"] # 删除元素
-
-
# 遍历数组(仅value)
-
for i in ${a[*]}
-
do
-
echo ${i}
-
done
-
-
# 遍历数组(key和value)
-
for key in ${!a[*]}
-
do
-
echo "${key} ==> ${a[${key}]}"
-
done
-
-
unset a # 清空数组
注:
- 关联数组需要bash 4.0以上版本才支持,选用需慎重。查看
bash
版本用bash --version
- 关联数组必须用
declare -A
显示声明类型,否则数值会出错。
第四式:将命令执行结果存入变量
` `与$( )
LINE_CNT=`wc -l test.txt`
LINE_CNT=$(wc -l test.txt)
以上命令均可把wc -l test.txt
的结果存入LINE_CNT
变量中
注:
` `
和$( )
都只将命令行标准输出的内容存入变量,如果需要将标准错误内容存入变量,需要用到重定向。
换行符处理
如果命令执行结果有多行内容,存入变量并打印时换行符会丢失:
devzkndeMacBook-Pro:test devzkn$ ls
test.sh test_for.sh
devzkndeMacBook-Pro:test devzkn$ cat test_for.sh
for i in `seq 1 3 20`
do
echo ${i}
done
devzkndeMacBook-Pro:test devzkn$ content=`cat test_for.sh`
devzkndeMacBook-Pro:test devzkn$ echo ${content}
for i in `seq 1 3 20` do echo ${i} done
devzkndeMacBook-Pro:test devzkn$
""
:
devzkndeMacBook-Pro:test devzkn$ echo "${content}"
for i in `seq 1 3 20`
do
echo ${i}
done
devzkndeMacBook-Pro:test devzkn$
正文(重点)
第五招:重定向
标准输入流、标准输出流、标准错误流
名称 | 英文缩写 | 内容 | 默认绑定位置 | 文件路径 | Shell中代号 |
---|---|---|---|---|---|
标准输入流 | stdin |
程序读取的用户输入 | 键盘输入 | /dev/stdin |
0 |
标准输出流 | stdout |
程序的打印的正常信息 | 终端(terminal ), 即显示器 |
/dev/stdin |
1 |
标准错误流 | stderr |
程序的错误信息 | 终端(terminal ),, 即显示器 |
/dev/stderr |
2 |
重定向方式一览表
操作 | 含义 |
---|---|
cmd > file | 把 stdout 重定向到 file |
cmd >> file | 把 stdout 追加到 file |
cmd 2> file | 把 stderr 重定向到 file |
cmd 2>> file | 把 stderr 追加到 file |
cmd &> file | 把 stdout 和 stderr 重定向到 file |
cmd > file 2>&1 | 把 stdout 和 stderr 重定向到 file |
cmd >> file 2>&1 | 把 stdout 和 stderr 追加到 file |
cmd file2 cmd | cmd 以 file 作为 stdin,以 file2 作为 stdout |
cat <>file | 以读写的方式打开 file |
cmd < file cmd | cmd 命令以 file 文件作为 stdin |
cmd << delimiter Here document | 从 stdin 中读入,直至遇到 delimiter 分界符 |
第一式:重定向标准输出流(stdout)
把程序打印的内容输出到文件
devzkndeMacBook-Pro:test devzkn$ echo 1+1 >exp.txt
devzkndeMacBook-Pro:test devzkn$ cat exp.txt
1+1
第二式:重定向标准错误流(stderr)
把程序的错误信息输出到文件
devzkndeMacBook-Pro:test devzkn$ ls +++ 2> err*
devzkndeMacBook-Pro:test devzkn$ cat err*
ls: +++: No such file or directory
devzkndeMacBook-Pro:test devzkn$ echo 1+1 >exp.txt
devzkndeMacBook-Pro:test devzkn$ cat exp.txt
1+1
devzkndeMacBook-Pro:test devzkn$ bc -q < exp.txt
2
devzkndeMacBook-Pro:test devzkn$ s="1+1"
devzkndeMacBook-Pro:test devzkn$ bc -q <<< "${s}"
2
3. 将当前shell脚本中的多行内容作为程序的输入
例如在shell中内嵌多行python代码:
devzkndeMacBook-Pro:test devzkn$ cat test_python.sh
python << EOF
print 'hello from python'
print 'hello'+'kevin'
EOF
devzkndeMacBook-Pro:test devzkn$ sh test_python.sh
hello from python
hellokevin
内容中支持shell变量
devzkndeMacBook-Pro:test devzkn$ cat test_python.sh
#python << EOF
#print 'hello from python'
#print 'hello'+'kevin'
#EOF
msg="shell variable"
python <<EOF
print '${msg}'
EOF
devzkndeMacBook-Pro:test devzkn$ sh test_python.sh
shell variable
- 以上重定向方法格式为:
命令 << EOF (换行)...(换行) EOF
,其中的EOF
换成其它字符串也是有效的,如:命令 << ABC (换行)...(换行) ABC
的,但通用习惯都使用EOF
devzkndeMacBook-Pro:test devzkn$ cat test_while.sh
line_no=0
cat test.sh |
while read line
do
((line_no++));
echo "${line_no} ${line}"
done
#echo "${line_no}"
devzkndeMacBook-Pro:test devzkn$ sh test_while.sh
1 s=$1;
2 if test -z ${s}
3
4 then
5 echo "empty"
6
7 fi
注:
read
命令用于从标准输入读取一行并赋值给一个或多个变量,如read LINE
会从标准输入读取一行并将整行内容赋值给LINE
变量,read A B
则会从标准输入读入一行并将这行的第1、2列分别赋值给A、B两个变量(分割符默认为空格或tab,可给IFS
赋值来更改分割符) > 2. 末尾注释掉的echo "${LINE_NO}"
若执行会输出0
,原因是管道中的while
语句是执行在子进程中的,不会改变父进程中LINE_NO
变量的值
ps:
devzkndeMacBook-Pro:test devzkn$ find . -type f -name \*.txt
./err.txt
./exp.txt
devzkndeMacBook-Pro:test devzkn$ find . -type f -name \*.txt | xargs
./err.txt ./exp.txt
xargs
直接接命令名称,则将从标准输入读取的所有内容合并为一行构建命令行并执行
devzkndeMacBook-Pro:test devzkn$ find . -type f -name \*.txt | xargs ls -l
-rw-r--r-- 1 devzkn staff 35 11 1 22:03 ./err.txt
-rw-r--r-- 1 devzkn staff 4 11 1 22:08 ./exp.txt
xargs
加上-i
参数,则会每读取一行就构建并执行一个命令行,构建命令行时会将{}
替换为该行的内容
-
有待尝试
-
[casheywen@ubuntu:~]# cat test.txt | xargs -i echo rm {}
-
rm a
-
rm b
-
rm c
hell通配的原理
如果你的当前目录中有1.txt 2.txt 3.txt
三个文件,那么当你执行ls *.txt
这条命令,shell
究竟为你做了什么?
其实shell
会先读取当前目录,然后按*.txt
的通配条件过滤得到1.txt 2.txt 3.txt
这个文件列表,然后将这个列表作为参数传给ls
,即ls *.txt
相当于ls 1.txt 2.txt 3.txt
,ls
命令本身并不会得到*.txt
这样的参数。
*.txt
通配的文件, shell
才会将 *.txt
这个字符串当作参数直接传给 ls
命令
txt
文件,我们使用echo *.txt
也同样可以达到目的:devzkndeMacBook-Pro:test devzkn$ echo *.txt
err.txt exp.txt
{ }
通配shell
不会读取目录并过滤获得文件列表。详细请参考下文 。
通配符一览表
字符 | 含义 | 实例 |
---|---|---|
* | 匹配 0 或多个字符 | a*b a与b之间可以有任意长度的任意字符, 也可以一个也没有, 如aabcb, axyzb, a012b, ab。 |
? | 匹配任意一个字符 | a?b a与b之间必须也只能有一个字符, 可以是任意字符, 如aab, abb, acb, a0b。 |
[list] |
匹配 list 中的任意单一字符 | a[xyz]b a与b之间必须也只能有一个字符, 但只能是 x 或 y 或 z, 如: axb, ayb, azb。 |
[!list] [^list] |
匹配 除list 中的任意单一字符 | a[!0-9]b a与b之间必须也只能有一个字符, 但不能是阿拉伯数字, 如axb, aab, a-b。 |
[c1-c2] |
匹配 c1-c2 中的任意单一字符 如:[0-9] [a-z] | a[0-9]b 0与9之间必须也只能有一个字符 如a0b, a1b... a9b。 |
{string1,string2,...} |
枚举sring1或string2(或更多)其一字符串 | a{abc,xyz,123}b 展开成aabcb axyzb a123b |
{c1..c2} {n1..n2} |
枚举c1-c2中所有字符或n1-n2中所有数字 | {a..f} 展开成a b c d e f a{1..5} 展开成a1 a2 a3 a4 a5 |
注:
*
、?
、[ ]
的通配都会按读取目录并过滤的方式展开通配项目{ }
则不会有读取目录的过程,它是通过枚举所有符合条件的通配项直接展开的
devzkndeMacBook-Pro:test devzkn$ ls -l {e..f}*.txt
ls: f*.txt: No such file or directory
-rw-r--r-- 1 devzkn staff 35 11 1 22:03 err.txt
-rw-r--r-- 1 devzkn staff 4 11 1 22:08 exp.txt
devzkndeMacBook-Pro:test devzkn$ echo {e..f}*.txt
err.txt exp.txt f*.txt
devzkndeMacBook-Pro:test devzkn$
*
通配的结果与目录中存在哪些文件有关系,而{ }
的通配结果与目录中存在哪些文件无关。若用{ }
进行通配,则有可能将不存在的文件路径作为命令行参数传给程序。生成序列
{ }
生成的序列常用于for循环
-
for ip in 192.168.234.{1..255}
-
do
-
ping ${ip} -w 1 &> /dev/null && echo ${ip} is Alive
-
done
以上例子用于查找
192.168.234.1~192.168.234.255
整个网段能ping
通的所有ip
1.1查看环境变量
devzkndeMacBook-Pro:test devzkn$ env
TERM_PROGRAM=Apple_Terminal
SHELL=/bin/bash
TERM=xterm-256color
总结
文章来源: kunnan.blog.csdn.net,作者:iOS逆向,版权归原作者所有,如需转载,请联系作者。
原文链接:kunnan.blog.csdn.net/article/details/43734761
- 点赞
- 收藏
- 关注作者
评论(0)