查看手册
man bash
重定向
2>&1 #错误重定向到标准输出
&> file #标准和错误都输出到file
1>&2 #标准输出重定向到错误
花括号{}
touch playground/dir-{00{1..9},0{10..99},100}/file-{A..Z}。#花括号可以嵌套
ls -A
ls -A 显示所有文件除了当前目录和上级目录. ..
切换目录
~username 表示用户的家目录
搜索历史命令
Ctrl-r搜索历史命令
Ctrl-j编辑搜索出来的历史命令
umask
umask (rw-rw-rw)-umask,比如umask=0002则,默认文件权限为rw-rw-r
目录比文件多了x权限默认目录权限rwx-rwx-r-x
root权限执行
su -c 'ls /root' 执行root权限而不切换到root
chown
chown bob: 文件所有者改为用户 bob,文件用户组改为,用户 bob 登 录系统时,所属的用户组。
:admins 把文件用户组改为组 admins,文件所有者不变。
vmstat
vmstat 2 5
表示隔2秒时间进行5次采样。
vmstat -d 查看磁盘的读/写
vmstat -S M 显示单位M
vim编辑器
w移动到下一个单词或标点符号的开头。
W 移动到下一个单词的开头,忽略标点符号。
b移动到上一个单词或标点符号的开头。
0移动到当前行的行首。
$移动到当前行的末尾。
^移动到当前行的第一个非空字符。
a光标在当前word后面插入
A光标在当前行的末尾插入
x 删除当前光标的字符
3x 当前字符及其后的两个字符。
d$ 从光标位置开始到当前行的行尾。
d0 从光标位置开始到当前行的行首。
dˆ 从光标位置开始到文本行的第一个非空字符。
dG 从当前行到文件的末尾。
dW 从光标位置开始到下一个单词的开头。
yy 当前行。
5yy 当前行及随后的四行文本。
yW 从当前光标位置到下一个单词的开头。
y$ 从当前光标位置到当前行的末尾。
y0 从当前光标位置到行首。
yˆ 从当前光标位置到文本行的第一个非空字符。
yG 从当前行到文件末尾。
y20G 从当前行到文件的第20 行。
p 命令把所复制的文本粘贴到当前行之下
P 命令把所复制的文本粘贴到当前行之上
J(不要与小写的j 混淆了,j 是用来移动光标的)把行与行之间连接起来。(非常实用)
:%s/Line/line/g
条目含义
: 冒号字符运行一个ex 命令。
% 指定要操作的行数。% 是一个快捷方式,表示从第一行到
最后一行。另外,操作范围也可以用1,5 来代替(因为我们
的文件只有5 行文本),或者用1,$ 来代替,意思是“从第
一行到文件的最后一行。”如果省略了文本行的范围,那么
操作只对当前行生效。
s 指定操作。在这种情况下是,替换(查找与替代)。
/Line/line 查找类型与替代文本。
g 这是“全局”的意思,意味着对文本行中所有匹配的字符串
执行查找和替换操作。如果省略g,则只替换每个文本行中
第一个匹配的字符串。
vi编辑多个文件
vim file1 file2 ...
n/N切换文件
n!/N!放弃更改并切换文件
:r foo.txt 将foo.txt的文件内容插入到当行的下一行
:w foo1.txt 保存副本
ZZ保存并退出
vim编写脚本常用设置
:syntax on #打开语法高亮
:set hlsearch #打开这个选项是为了高亮查找结果
:set tabstop=4 #设置一个tab 字符所占据的列数。默认是8 列。
:set autoindent #新的文本行缩进与刚输入的文本行相
同的列数
元数据
stat example.txt查看文件的元数据
ls -i example.txt
df -i 查看分区的inode信息
find
find
find命令搜索出来是无序的
find ~ \( -type f -not -perms 0600 \) -or \( -type d -not -perms 0700 \)
find playground \( -type f -not -perm 0600 -exec chmod 0600 '{}' ';' \)
-or \( -type d -not -perm 0711 -exec chmod 0700 '{}' ';' \)
find ~ -type f -name '*.BAK' -delete
find ~ -type f -name 'foo*' (-ok|-exec) ls -l '{}' ';' #{} 是当前路径名的符号表示,分号是要求的界
定符表明命令结束。
find . -type f -size +100M -print0 | xargs -0 du -h
find . -iname ‘*.jpg’ -print0 | xargs –null ls -l
find . -type f -exec ls -l {} \;
find ~ -type f -name 'foo*' -exec ls -l '{}' ';' #找到一个文件就执行一次ls -l
find ~ -type f -name 'foo*' -exec ls -l '{}' + #全部参数都找到了再一次性执行一次ls -l
find ~ -type f -name 'foo\*' -print | xargs ls -l
find ./ -type f -name "*.sh"|xargs -i mv {} /opt/ # 加-i 参数直接用 {}就能代替管道之前的标准输出的内容;
find . -type f -name "*.log" | xargs -I {} cp {} /tmp/n/ #加 -I 参数 需要事先指定替换字符。
#xargs 会为ls 命令构建参数
列表,然后执行ls 命令,也是只执行一次ls,如果参数过长
xargs
cat exsample.txt |xargs #多行转化成1行输出
cat exsample.txt |xargs -n 2 #每行显示2个参数-L 和-n区别在文件名不会因为空格而被分开
echo helloXwelcomeXworld |xargs -d X #-d设置定界符X
cat args.txt |xargs -n 1 ./cecho.sh #将格式化参数传递给脚本,可代替for循环
cat args.txt |xargs -I {} ./cecho.sh -p {} -1 #-I替换
-i默认{},-I 可以指定其他替换字符
-P 指定并发数
rsync
rsync -av --delete /etc /home /usr/local /media/BigDisk/backup #--delete删除可能在目的设备中已经存在但却不再存在于源设备中的文件
grep
grep -l bzip dirlist*.txt #打印包含匹配项的文件名,而不是文本行本身
-L#相似于-l 选项,但是只是打印不包含匹配项的文件名
-n#在每个匹配行之前打印出其位于文件中的相应行号
-c#打印匹配的数量
-v#打印不匹配的行
-h#查询多文件时不显示文件名。
正则表达
BRE 可以辨别以下元字符:^ $ . [ ] *
ERE 添加了以下元字符: ( ) { } ? + |
BRE 中,字符“(”,“)”,“{”,和“}”用反斜杠转义后,
被看作是元字符, 相反在ERE 中,在任意元字符之前加上反斜杠会导致其被看作是一个文本字
符。
sort
sort -t ':' -k 7 /etc/passwd | head #-t 选项来定义分隔符
sort -k 3.7nbr -k 3.1nbr -k 3.4nbr distros.txt -o newfile.txt
#-o输出到文件,-k 3.7第三个地段的第7个字符开始排序-b忽略每行开头的空格,从第一个非空白字符开始排序-n根据数字值执行排序,而不是字母值。-r降序。-u消除重复行
uniq
-d 只输出重复行
-i 在比较文本行的时候忽略大小写。
cut
cut -d ':' -f 1 /etc/passwd
tr
echo "lowercase letters" | tr [:lower:] A #所有小写转化为A
echo "lowercase letters" | tr a-z A-Z #小写转大写
sed
echo "aaabbbccc" | sed 's/b/B/g' #全部替换b为B
awk传递外部变量
awk '{print v1 v2}' v1=$var1 v2=$var2
awk '{count[$0]++}END{for(i in count){printf("word%-14s %d\n",i,count[i])}}' #使用for循环
awk 'NR==3,NR==5' exsample.txt #打印3-5行直接的文本
awk '/star_pattern/,/end_pattern/' exsample.txt #对应pattern直接的文本
函数
[ function ] funname [()]
{
action;
[return int;]
}
function funct #函数名必须和{之间有空格
{
echo "Step 2"
return
}
func2() {
echo "func2"
return
}
#在脚本中shell 函数定义必须出现在函数调
用之前。
funct
func1
func2
unset -f func #删除函数
说明:
(1)可以带function fun() 定义,也可以直接fun() 定义,不带任何参数。
(2)参数返回,可以显示加:return 返回,如果不加,将以最后一条命令运行结果,作为返回值。 return后跟数值n(0-255),还可以通过echo 直接返回。
注意
shell中通过return返回是有限制的,最大返回255,超过255,则从0开始计算。
#!/bin/sh
echo "shell function operation"
func1()
{
local num1=100
local num2=100
let sum=$num1+$num2
return $sum
}
func2()
{
local num1=100
local num2=155
let sum=$num1+$num2
return $sum
}
func3()
{
local num1=100
local num2=156
let sum=$num1+$num2
return $sum
}
func4()
{
local num1=100
local num2=156
let sum=$num1+$num2
echo $sum
}
func1
echo "called func1:$?"
func2
echo "called func2:$?"
func3
echo "called func3:$?"
sum=`func4`
echo "called func4:$sum"
执行结果如下所示:
cat
cat <<\_EOF_ #<<\反斜杠的作用是禁止拓展,也就是输入啥就是啥
cat -s压缩空行
cat -n f1.txt,查看f1.txt文件的内容,并且由1开始对所有输出行进行编号。
cat -b f1.txt,查看f1.txt文件的内容,用法与-n相似,只不过对于空白行不编号。
cat -s f1.txt,当遇到有连续两行或两行以上的空白行,就代换为一行的空白行。
局部变量
foo=0
funct_1 () {
local foo #定义局部变量,不影响外部变量foo
foo=1
echo "funct_1: foo = $foo"
}
funct_1
echo $foo
#结果如下
#funct_1: foo = 1
#0
if
[[ string1 =~ regex ]]#regex不能加引号,否则不匹配
if [[ "$INT" =~ ^[0-9]+$ ]] #匹配整数
if [[ $INT =~ ^-?[[:digit:]]+$ ]]
[[ ]] 添加的另一个功能是== 操作符支持类型匹配,正如路径名展开所做的那样。如:
if [[ $FILE == foo.* ]] #正则表达式也不能加引号,否则不匹配
&&,||,-a,-o,!用法
if [[ $1 -gt 1 && $1 -gt 5 ]]
if [ $1 -gt 1 -a $1 -gt 5 ]
if [ $1 -gt 1 ] && [ $1 -gt 5 ]
追踪脚本
方法1:
sh -x script.sh
方法2: 在脚本中set 命令加上-x 选项,为脚本中的一块选择区域,而不是整个脚本启用追 踪。set 命令加上-x 选项来启动追踪,+x 选项关闭追踪,如
#!/bin/bash
# trouble: script to demonstrate common errors
number=1
set -x # Turn on tracing
if [ $number = 1 ]; then
echo "Number is equal to 1."
else
echo "Number is not equal to 1."
fi
set +x # Turn off tracing
or || and &&
mkdir temp && cd temp #只有如果command1执行成功后,才会执行command2。
[ -d temp ] || mkdir temp #只有如果command1 执行失败后,才会执行command2
case
#!/bin/sh
echo "Test Of CASE"
case $1 in
1)
echo "1"
;;
a|A)
echo "a|A"
;;& #添加的“;;&”的语法允许case 语句继续执行下一条测试,而不是简单地终止运行。
[[:alpha:]])
echo "alpha"
;;&
???)
echo "three character"
;;
[ABC][0-9])
echo "[ABC][0-9]"
;;
*.txt)
echo "*.txt"
;;
*)
参数
$0 文件名 $n 第N个参数 $# 参数个数 $* 和$@的区别在于加双引号之后被看做是单个字符串 $@ $!Shell最后运行的后台Process的PID $$脚本运行的当前进程ID号 $?最后运行的命令的结束代码(返回值)即执行上一个指令的返回值
大小写转换
方法1:
#!/bin/bash
# ul-declare: demonstrate case conversion via declare
declare -u upper
declare -l lower
if [[ $1 ]]; then
upper="$1"
lower="$1"
echo $upper
echo $lower
fi
方法2:
#bash3.x
$ echo $VAR_NAME | tr '[:upper:]' '[:lower:]'
$ echo $VAR_NAME | tr '[:lower:]' '[:upper:]'
#bash4.x
${parameter„} 把 parameter 的值全部展开成小写字母。
${parameter,} 仅仅把 parameter 的第一个字符展开成小写字母。
${parameterˆˆ} 把 parameter 的值全部转换成大写字母。
${parameterˆ} 仅仅把 parameter 的第一个字符转换成大写字母(首字母 大写))
加一减一
let c++/c--
$((++foo)) #先加再返回
$((foo++)) #先返回再加
[me@linuxbox~]$ foo=1
[me@linuxbox~]$ echo $((++foo))
2
[me@linuxbox~]$ echo $foo
2
[me@linuxbox~]$ foo=1
[me@linuxbox~]$ echo $((foo++))
2
[me@linuxbox~]$ echo $foo
2
三元运算符号
[me@linuxbox~]$ a=0
[me@linuxbox~]$ ((a<1?++a:--a))
[me@linuxbox~]$ echo $a
1
[me@linuxbox~]$ ((a<1?++a:--a))
[me@linuxbox~]$ echo $a
0
数组
declare -a array1 #下标数字
declare -A colors。#下标可以是其它
colors["red"]="#ff0000"。
colors["green"]="#00ff00"
colors["blue"]="#0000ff"
name[subscript]=value
name=(value1 value2 ...)
days=([0]=Sun [1]=Mon [2]=Tue [3]=Wed [4]=Thu [5]=Fri [6]=Sat)
输出整个数组的内容*和@区别
[me@linuxbox ~]$ animals=("a dog" "a cat" "a fish")
[me@linuxbox ~]$ for i in ${animals[*]}; do echo $i; done
a
dog
a
cat
a
fish
[me@linuxbox ~]$ for i in ${animals[@]}; do echo $i; done
a
dog
a
cat
a
fish
[me@linuxbox ~]$ for i in "${animals[*]}"; do echo $i; done
a dog a cat a fish
[me@linuxbox ~]$ for i in "${animals[@]}"; do echo $i; done
a dog
a cat
a fish
确定数组元素个数
[me@linuxbox ~]$ a[100]=foo
[me@linuxbox ~]$ echo ${#a[@]} # 数组元素个数
1
[me@linuxbox ~]$ echo ${#a[100]} #元素长度
3
数组使用的下标
[me@linuxbox ~]$ foo=([2]=a [4]=b [6]=c)
[me@linuxbox ~]$ for i in "${foo[@]}"; do echo $i; done
a
b
c
[me@linuxbox ~]$ for i in "${!foo[@]}"; do echo $i; done
2
4
6
for
for var;do : ;done
等同于
for var in "$@";do : ;done
数组末尾添加元素
[me@linuxbox~]$ foo=(a b c)
[me@linuxbox~]$ echo ${foo[@]}
a b c
[me@linuxbox~]$ foo+=(d e f)
[me@linuxbox~]$ echo ${foo[@]}
a b c d e f
删除数组
[me@linuxbox ~]$ foo=(a b c d e f)
[me@linuxbox ~]$ echo ${foo[@]}
a b c d e f
[me@linuxbox ~]$ unset foo
[me@linuxbox ~]$
删除单个元素
[me@linuxbox~]$ foo=(a b c d e f)
[me@linuxbox~]$ echo ${foo[@]}
a b c d e f
[me@linuxbox~]$ unset 'foo[2]' #数组元素必须用引号引起来为的是防止shell 执行路径名展开操作
[me@linuxbox~]$ echo ${foo[@]}
a b d e f
任何引用一个不带下标的数组变量,则指的是数组元素0:
[me@linuxbox~]$ foo=(a b c d e f)
[me@linuxbox~]$ echo ${foo[@]}
a b c d e f
[me@linuxbox~]$ foo=A
[me@linuxbox~]$ echo ${foo[@]}
A b c d e f
组命令和子 shell
组命令: { command1; command2; [command3; …] } #花括号与命令之间必须有一个空格,并且最后一 个命令必须用一个分号或者一个换行符终止。 子 shell (command1; command2; [command3;…]) 案例: { ls -l; echo “Listing of foo.txt”; cat foo.txt; } > output.txt #会把三条命令的输出结果分别重定向到output.txt
组命令和子shell区别在于 组命令在当前 shell 中执行它的所有命令,而一个子 shell(顾 名思义)在当前 shell 的一个子副本中执行它的命令。 组命令运行很快并且占用的内存也少。
创建临时文件
tempfile=$(mktemp /tmp/foobar.$$.XXXXXXXXXX) #$$表示当前进程号
mktemp -u new.XXX #不创建任何东西,仅仅显示文件名,至少三个大写的XXX
mktemp -d benderfly.XXXXXX #创建临时目录
wait
等待子进程执行完毕,用在脚本中调用子进程
child-process &
pid=$!
wait $pid #等待最近那个后台进程结束
IFS分隔符
oldIFS=$IFS
录制终端会话
script -t 2> timing.log -a output.session #录制终端会话 scriptreplay timing.log output.session #回放终端会话
readlink读取软连接
readlink 找出符号链接所指向的位置
[root@login4 WRF]# readlink --help
用法:readlink [选项]... 文件...
输出符号链接值或权威文件名。
-f, --canonicalize 递归跟随给出文件名的所有符号链接以标准化,
除最后一个外所有组件必须存在
-e, --canonicalize-existing 递归跟随给出文件名的所有符号链接以标准化,
所有组件都必须存在
-m, --canonicalize-missing canonicalize by following every symlink in
every component of the given name recursively,
without requirements on components existence
-n, --no-newline do not output the trailing delimiter
-q, --quiet,
-s, --silent suppress most error messages
-v, --verbose report error messages
-z, --zero separate output with NUL rather than newline
--help 显示此帮助信息并退出
--version 显示版本信息并退出
bc比较两个数大小
[root@www test]# echo $a
98.7
[root@www test]# echo $b
89.34
[root@www test]# echo "$a > $b"|bc
1
[root@www test]# echo "$b > $a"|bc
0
local局部和全局变量
变量分类
局部变量和环境变量,局部变量只适用于当前shell,而环境变量是全局的,它适用于所有当前shell以及其派生出来的任意子进程
局部变量
局部变量的作用域被限定在创建它们的shell中。
local函数可以用来创建局部变量,但仅限于函数内使用。
局部变量可以通过简单的赋予它一个值或一个变量名来设置。
用declare内置函数来设置,或者省略也可。
格式:
local 变量名=值 #仅限于函数内部使用
变量名=值
declare 变量名=值
局部变量的例子:
[root@www test]# round=world
[root@www test]# echo $round
world
[root@www test]# bash
[root@www test]# echo $round
[root@www test]# exit
exit
[root@www test]# echo $round
world
在上面的岩石中可以看出,当启动一个bash程序,相当于创建一个子shell后,round变在这个子shell中没有被赋值,exit退出子shell后,可以看到父shell中变量round仍有值。
环境变量
环境变量通常又称全局变量,以区别于局部变量,通常,环境变量应该大写,环境变量是已经用export内置命令导出的变量。子shell继承当前父shell的环境变量,并能一直传承下去,但是不可逆向传递。 格式:
export 变量=值
declare -x 变量=值
我们做个示范:
[root@www test]# export NAME="benderfly"
[root@www test]# echo $NAME
benderfly
[root@www test]# bash
[root@www test]#
[root@www test]# echo $NAME
benderfly
[root@www test]# declare -x NAME="Arvin"
[root@www test]# echo $NAME
Arvin
[root@www test]# exit
exit
[root@www test]# echo $NAME
benderfly
上述例子中,父shell中定义的NAME环境变量传递到了子shell中,在子shell中定义的NAME环境变量没有被带到父shell中。
设置变量的三种方法
1) 在/etc/profile文件中添加变量【对所有用户生效(永久的)】 例如:
# vi /etc/profile
export CLASSPATH=./JAVA_HOME/lib;$JAVA_HOME/jre/lib
注:修改文件后要想马上生效还要运行
source /etc/profile 不然只能在下次重进此用户时生效。
2) 在用户目录下的.bash_profile文件中增加变量【对单一用户生效(永久的)】 例如:编辑guok用户目录(/home/guok)下的.bash_profile
$ vi /home/guok/.bash.profile
export CLASSPATH=./JAVA_HOME/lib;$JAVA_HOME/jre/lib
注:修改文件后要想马上生效还要运行
source /home/guok/.bash_profile 不然只能在下次重进此用户时生效。
3) 直接运行export命令定义变量【只对当前shell(BASH)有效(临时的)】 在shell的命令行下直接使用[export变量名=变量值]定义变量, 该变量只在当前的shell(BASH)或其子shell(BASH)下是有效的,shell关闭了,变量也就失效了,再打开新shell时就没有这个变量,需要使用的话还需要重新定义。
bash_profile,.bash_profile和.bashrc的区别
/etc/profile:此文件为系统的每个用户设置环境信息,当用户第一次登录时,该文件被执行. 并从/etc/profile.d目录的配置文件中搜集shell的设置. /etc/bashrc:为每一个运行bash shell的用户执行此文件.当bash shell被打开时,该文件被读取. ~/.bash_profile:每个用户都可使用该文件输入专用于自己使用的shell信息,当用户登录时,该 文件仅仅执行一次!默认情况下,他设置一些环境变量,执行用户的.bashrc文件. ~/.bashrc:该文件包含专用于你的bash shell的bash信息,当登录时以及每次打开新的shell时,该 该文件被读取. ~/.bash_logout:当每次退出系统(退出bash shell)时,执行该文件.
另外,/etc/profile中设定的变量(全局)的可以作用于任何用户,而~/.bashrc等中设定的变量(局部)只能继承/etc/profile中的变量,他们是”父子”关系.
~/.bash_profile 是交互式、login 方式进入 bash 运行的 ~/.bashrc 是交互式 non-login 方式进入 bash 运行的 通常二者设置大致相同,所以通常前者会调用后者。
设置生效:可以重启生效,也可以使用命令:source alias php=/var/eyouim/pub/php/bin/php source /etc/profile
”:”的作用
·啥也不做,只起到占位符的作用
脚本注释、占位符
#!/bin/sh
: this is single line comment
: 'this is a multiline comment,
second line
end of comments'
if [ "1" == "1" ]; then
echo "yes"
else
:
fi
参数拓展
${parameter:-word} 如果parameter没有设置或者为空,替换为word;否则替换为parameter的值
${parameter:+word} 如果parameter没有设置或者为空,不进行任何替换;否则替换为word。
${parameter:=word} 如果parameter没有设置或者为空,把word赋值给parameter。实际parameterd的值真的被替换了,这就是=号的意思。不能用这种方式指派位置参数或特殊参数的值。
${parameter:?word} 如果parameter没有设置或者为空,把word输出到stderr,否则替换为parameter的值。
-、+、? 实际parameter的值并不被修改,扩展只是临时显示成word的值。准确的讲,扩展实际替换的是参数的显示,而不是参数的定义。只有=,才是替换参数的定义。
${parameter:offset} 扩展为parameter中从offset开始的子字符串。
${parameter:offset:length} 扩展为parameter中从offset开始的长度不超过length的字符。
清空文件
: >file
清空文件file的内容。
参数拓展
[root@node56 ~]# : abc=1234
[root@node56 ~]# echo $abc
[root@node56 ~]# : ${abc:=1234}
[root@node56 ~]# echo $abc
1234
[root@node56 ~]# ${abc:=1234}
-bash: 1234: command not found
格式:: ${VAR:=DEFAULT}
当变量VAR没有声明或者为NULL时,将VAR设置为默认值DEFAULT。如果不在前面加上:命令,那么就会把${VAR:=DEFAULT}本身当做一个命令来执行,报错是肯定的。 可以看出来,如果${abc:=1234}前面不加”:”的话,会直接把他当作命令执行