• curl用法
  • 在单行命令里设置环境变量
  • set
  • 查看磁盘信息(型号, 容量等)
  • 查看磁盘是否SSD
  • sshfs挂载/卸载
    • line-by-line方式合并2个文件
    • exec, source, fork的区别(参考: Shell十三问)
  • 获取当前TTY的名字/限制脚本仅能在TTY中执行
  • 只能root用户运行脚本

curl用法

安装最新版curl
rpm -Uvh http://nervion.us.es/city-fan/yum-repo/rhel6/x86_64/city-fan.org-release-1-13.rhel6.noarch.rpm
yum install -y curl 获取本机IP地址
curl -s -4 icanhazip.comcurl不显示下载进度:
curl http://www.baidu.com 2>/dev/nullcurl携带cookie
curl 'http://xxx.xxx' -b 'NAME1=VALUE1;NAME2=VALUE2'curl统计请求时间(单位: 秒)
curl -w '%{time_total}' 'http://www.sogou.com'绑定host, 主要用于解决服务器端根据server_name为VirtualHost作反向代理
curl -H 'Host: web.pc.le.com' 'http://10.110.92.208/ip_geo?xxx=xxx'使用curl,拷贝本地文件,优势在于可以显示复制进度
http://stackoverflow.com/questions/21023048/copying-local-files-with-curl
curl file:///path/to/source/file -o /path/to/destination使用curl的GET方式发送中文值
curl -XGET --cookie "userId=1"  'http://i.api.cms.music.le.com:3000/ui/homePage/favorite/search' -G --data-urlencode 'keyword=组'BasicAuth:
curl -u 'abc:pwd@x:' -XPOST 'http://10.8.131.217:3000/api/v1/sql/read' -H 'Content-type: application/json' -d '{"sql": "select * from my_tbl"}'
或
curl -XPOST 'http://abc:1234@10.8.131.217:3000/api/v1/sql/read' -H 'Content-type: application/json' -d '{"sql": "select * from my_tbl"}'# 指定多个Header
curl www.cyberciti.biz \
-H "Accept-Language: en" \
-H "Host www.cyberciti.biz" \
-H "User-Agent: curl"# 上传文件+发送参数
curl -XPOST 'http://kpitracker.top/kpi/api/v1/updown/upload_pic?token=4fc0099e-cdb8-4e37-9762-62a866350a20'\-F 'longitude=12.3456'\-F 'latitude=45.6123'\-F 'file=@/Users/lishaolin/Desktop/datetime转换.jpeg'

在单行命令里设置环境变量

$ MY_VAR='Hello' ANOTHER_VAR='World!!!' && echo "$MY_VAR $ANOTHER_VAR"
Hello World!!!$ MY_VAR='Hello' ANOTHER_VAR='World!!!' && echo "$MY_VAR $ANOTHER_VAR"
Hello World!!!

set

#!/bin/bash

# 打印每一行脚本
set -x# 发生错误后, 立即退出
set -els /sxxls

查看磁盘信息(型号, 容量等)

root@ubuntu:~# hdparm -i /dev/sda1/dev/sda1:Model=HP SSD S700 120GB, FwRev=Q0616B1, SerialNo=HBSA17423600488Config={ Fixed }RawCHS=16383/16/63, TrkSize=0, SectSize=0, ECCbytes=0BuffType=unknown, BuffSize=unknown, MaxMultSect=1, MultSect=offCurCHS=16383/16/63, CurSects=16514064, LBA=yes, LBAsects=234441648IORDY=on/off, tPIO={min:120,w/IORDY:120}, tDMA={min:120,rec:120}PIO modes:  pio0 pio1 pio2 pio3 pio4DMA modes:  mdma0 mdma1 mdma2UDMA modes: udma0 udma1 udma2 udma3 udma4 udma5 *udma6AdvancedPM=yes: unknown setting WriteCache=enabledDrive conforms to: unknown:  ATA/ATAPI-4,5,6,7* signifies the current active mode

查看磁盘是否SSD

方法一
判断cat /sys/block/*/queue/rotational的返回值(其中*为你的硬盘设备名称,例如sda等等),如果返回1则表示磁盘可旋转,那么就是HDD了;反之,如果返回0,则表示磁盘不可以旋转,那么就有可能是SSD了。[cheshi@cheshi-laptop2 ~]$ cat /sys/block/nvme0n1/queue/rotational
0
[cheshi@cheshi-laptop2 ~]$ grep ^ /sys/block/*/queue/rotational
/sys/block/dm-0/queue/rotational:0
/sys/block/dm-1/queue/rotational:0
/sys/block/dm-2/queue/rotational:0
/sys/block/nvme0n1/queue/rotational:0
/sys/block/sda/queue/rotational:1
[cheshi@cheshi-laptop2 ~]$
1
2
3
4
5
6
7
8
9
这种方法有个问题,那就是/sys/block/下面不只有硬盘,还可能有别的块设备,它们都在干扰你的判断。方法二
使用lsblk命令进行判断,参数-d表示显示设备名称,参数-o表示仅显示特定的列。[cheshi@cheshi-laptop2 ~]$ lsblk -d -o name,rota
NAME    ROTA
nvme0n1    0
[cheshi@cheshi-laptop2 ~]$
1
2
3
4
这种方法的优势在于它只列出了你要看的内容,结果比较简洁明了。还是那个规则,ROTA是1的表示可以旋转,反之则不能旋转。

sshfs挂载/卸载

sshfs user_name@192.168.1.100:/path/to/remote/dir /path/to/local/dirumount -f /path/to/local/dir
1.SED
SED不支持\d和\+,所以只能用[0-9]和\{1,\}来替代。
sed -n '/INSERT INTO /p' ~/Desktop/tmp.txt | sed -n '/change_history/!p' | sed -n '/SQL .\{1,\}/p'macOS的sed不支持\tSED中,小括号和大括号,要对开和闭,都转义;中括号,只需要转义开就可以了,如果想转义闭,也没问题。
sed -n '/INSERT INTO /p' ~/Desktop/tmp.txt | sed -n '/change_history/!p' | sed -n 's/SQL .*\(INSERT INTO .*\) \[[0-9]*-[0-9]*\]/\1/p’与符号(&)用来替换命令中的匹配模式,不管预定义模式是什么文本,你都能用&符号在替换模式中引用它
echo 'The cat sleeps in his hat' |sed 's/.at/"&"/g'
输出为
The "cat" sleeps in his "hat"\1,\2,...,\n用于引用分组
echo "That furry cat is pretty" | sed 's/furry \(cat\)/\1/'
输出为
That cat is pretty# 插入新行的时候,如果要保留行首的空格, 应该使用反斜线(\)转义第一个空格
# http://www.linuxquestions.org/questions/programming-9/sed-insert-line-with-leading-spaces-866217/
sed -i "/^master: 192.168.1.74/{\
a\
master:
a\
\  - 192.168.1.74
a\
\  - 192.168.1.52
d
}" test.txt2.tmux
tmux list-sessions
tmux kill-session -t 0
tmux new-session -s mysession
tmux attach-session -t mysession3.Bash使用echo输出换行符:
echo -e 'a\nb'
或者
echo $'a\nb'4. Linux命令行与Shell脚本编程大全
区分文件、文件夹、可执行文件、连接
ls -F递归list
ls -R文件类型,文件权限,硬连接数,owner,group,大小(Byte),修改时间,文件名
ls -l以human可以阅读的形式显示文件的size
ls -sh显示文件的inode
ls -i获得系统变量值
getconf PAGESIZE递归目录copy
cp -R dir1 dir2保留文件属性(如最后修改时间等)
cp -p test1 test3强制覆盖已经存在的目录
cp -f test* dir2创建文件连接(硬连接,即file1和file2的inode号相同,硬连接数也相同),而非复制文件
cp -l file1 file2创建一个符号连接(软连接,即file1和file2的inode号不相同,硬连接数也不相同),而非复制文件
cp -s file1 file2cp软/硬连接,都是copy的软/硬连接的源文件,不是连接文件!rm软连接,不会导致软连接的源文件被remove;rm硬连接时,如果此时该硬连接指向的源文件(用inode编号区别)的硬连接数==1,那么就要remove这个硬连接指向的源文件了mv软连接,会导致软连接指向无效的源文件
mv可以move目录(跟cp和rm相比,不需要加-R参数)硬连接只能在相同的挂载点上使用,即不能在不同的挂载点下的文件间创建硬连接查看文件统计信息(-x用于标注每个字段的名字,貌似Linux发行版不需要使用这个参数,Mac OS需要使用)
stat -x file1查看文件类型(文本文件,可执行文件,数据文件)
file file以带行号(number)的形式查看文件
cat -n file1不给空白行(blank)加行号
cat -b file1把多个空白行压缩(squeeze)成单个空白行
cat -s file1cat管道
cat <<_EOF | clickhouse-client --database=test --query="INSERT INTO test FORMAT CSV";
3, 'some text', '2016-08-14 00:00:00'
4, 'some more text', '2016-08-14 00:00:01'
_EOF查看file1的最后10行
tail -n 10 file1让tail程序一直保持活动状态,如果有新的内容加到文件的末尾,就立即显示出来
tail -f file1让tail程序一直保持活动状态,如果有新的内容加到文件的末尾,就隔2秒钟再显示出来(Mac OS 不支持 -s 参数)
tail -f -s 2 file 1让tail程序一直保持活动,并且,如果file1被重命名或者inode改变,那么tail会reopen文件,优先使用同名文件名,然后使用同inode的文件
tail -F file1####第4章####
列出所有进程,并显示user列
ps aux
STAT列第一个字母:
S => Sleeping
R => Runnable
U => Uninterruptible wait
I => Idle
T => sTopped
Z => Zoombie
后面几个字母:
< => 高优先级
N => 低优先级
L => 该进程有页面锁定在内存
s => 控制进程
l => 多线程
+ => 运行在前端实时监测进程
top
Load Avg显示三个值,分别表示1分钟、5分钟、15分钟系统的平均负载,值越大,表明负载越重
在top运行的时候,使用o参数,可以指定某一列为主排序列,使用正(+)负(-)号表示升序/降序排列;使用O参数,可以指定某一列为次排序列;默认如果不指定正负号,默认使用负号,即降序排序杀死(默认发送TERM信号)进程号(PID)为1234的进程
kill 1234可以为kill指定信号名字或值,如发送Interrupt信号
kill -s INT 1234
或
kill -INT 1234
或
kill -2 1234还有屡试不爽的-9(KILL)信号:
kill -s KILL 1234
或
kill -KILL 1234
或
kill -9 1234这些信号的建议使用顺序是:先TERM,再INT/HUP,最后才是KILL挂载文件系统
mount -t type device directory
其中:
type可以是:vfat(Windows FAT16/32等),ntfs(NTFS),iso9660(CD-ROM)以只读权限把/dev/sdb1挂载到/media/disk上
mount -r -t vfat /dev/sdb1 /media/diskmount默认使用-w(可读可写)权限卸载/media/disk上挂载的文件系统
umount /media/disk显示磁盘剩余空间(并以人类可阅读的形式显示),可以间接查看自己已经挂载了哪些设备
df -h显示当前文件夹中各占用的磁盘空间及总空间,以人类可阅读的方式显示
du . -ch把/etc/passwd按照冒号(:)分割,按照第3列(从1开始数)的数字值升序排序
sort -t ':' -k 3 -n /etc/passwd# http://blog.csdn.net/zahuopuboss/article/details/53890789
sort -u txt
# 相当于
sort txt|uniq输出不匹配某个模式的行(ack同),如果pattern1中有空格或特殊字符(如pattern 1),请使用单引号包围:'pattern 1'
grep -v pattern1 file1输出匹配某个模式的行和行号(ack不同)
grep -n pattern1 file1多少行匹配某个模式(ack同)
grep -c pattern1 file1满足多个模式中任何一个(ack不同)
grep -e pattern1 -e pattern2 file1在显示匹配到的模式所在的行的时候,该行的上下各显示5行(ack同),注意C和5之间没有空格!
grep -C5 pattern1 file1仅显示匹配的字符串,而不是显示一整行,使用-o参数
curl 'http://10.183.95.56/deploy/server_info' |grep -o '[0-9a-f]\{40\}'查找当前目录及子目录中,相对路径+文件名符合某个模式的文件(grep不支持)
ack -g 'filepattern1'把2个文件夹归档成一个test.tar文件,注意,v参数可加可不加,仅用于显示归档的细节,f参数的右边,必须跟着tar文件的名字,不管归档还是解档
tar -cf test.tar test1/ test2/
或
tar -cvf test.tar test1/ test2/列出(list)归档文件里的文件或目录结构(仅list,不解档)
tar -tf test.tar解档test.tar到当前目录
tar -xf test.tar解档test.tar到/tmp目录,-C是切换目录,即切到另一个目录里执行tar操作
tar -xf test.tar -C /tmp
以下是man tar中对-C的解释:
-C directoryIn c and r mode, this changes the directory before adding the following files.  In x mode, change directories after opening the archive but beforeextracting entries from the archive.
我更倾向于认为-C是copy的意思。对于.tgz或.tar.gz的文件,在解档时,应该额外使用z参数
tar -xzf test.tar.gz
对于.tar.bz2的文件,在解档时,应该额外使用j参数
tar -xjf test.tar.gz# tar仅解压某几个文件
# http://asmboy001.blog.51cto.com/340398/288759
tar -xvf hr9pre_2_120809.tar /opt/oracle/product/10.2.0/dbs/orapwhr9pretar命令可以和nc命令结合可以快速在两台机器之间传输文件和目录:
B机器:
nc -l 5555 |tar -C /tmp/test/ -xf -
A机器:
tar cf - /tmp/test/ |nc B'IP 5555打包时,排除node_modules和.git目录
tar -czf ~/Desktop/thrift_socket_demo.tar.gz --exclude='node_modules' --exclude='.git’ .使用tar创建压缩包,输出到标准输出,并用gzip压缩,转存成tar.gz文件
(cd ../files && tar cf - results.*.log) | gzip -9 > ../archives/archive.tar.gz
比如,tar命令可以和nc命令结合可以快速在两台机器之间传输文件和目录:
B机器:
nc -l 5555 |tar -C /tmp/test/ -xf -
A机器:
tar cf - /tmp/test/ |nc B'IP 5555
上述步骤将A机器/tmp/test/下的内容拷贝到B机器对应的目录中,其中tar cf - /tmp/test/ |nc B'IP 5555 将内容边打包边通过管道和nc命令传输到由对应IP地址和5555端口传到B机器,nc -l 5555 |tar -C /tmp/test/ -xf - 监听本机的555端口,并将接收到的内容解包至指定的目录(-C参数指定目标目录)#tar -czf b.tar.gz tmp.txt -C ~/Desktop/  #!!!错误!!!
#tar: tmp.txt: Cannot stat: No such file or directory
#tar: Error exit delayed from previous errors.
在创建*.tar.gz的时候,需要先指定需要切换的目录,再创建文件,其含义是:切换到~/Desktop/,将~/Desktop/目录下的tmp.txt文件,压缩成t.tar.gz,并保存至当前目录(一般不是~/Desktop/)
tar -C ~/Desktop/ -czf t.tar.gz tmp.txt  #!!!正确!!!
相当于
tar -czf ./t.tar.gz ~/Desktop/tmp.txt
这与加压的时候-C切换目录不同
tar -xzf t.tar.gz -C ~/Desktop
含义是,切换到~/Desktop/,解压当前目录(一般不是~/Desktop/)下的t.tar.gz到~/Desktop/# 排除个别文件夹(排除et目录下的venv, .tox, .git, .cache)
tar czf et.tar.gz --exclude venv --exclude .tox --exclude .git --exclude .cache et####第5章####
查看全局环境变量
printenv查看特定进程设置的环境变量,也包括全局环境变量
set# 把执行的每一行脚本都显示出来
set -x# 脚本发生错误后, 立即退出
set -e设置局部环境变量(等号左右,不能有空格!)
my_var_name1=my_var_value
显示环境变量的值
echo $my_var_name1
如果要给变量赋一个含有空格的字符串值,那么必须用单引号来界定字符串的开始和结尾
my_var_name2='This is a long value'自己定义的环境变量,建议使用小写字母,这样可以区分用户个人环境变量和系统环境变量创建全局环境变量
先创建局部变量
my_var_name1=my_var_value
再将这个局部变量导出
export my_var_name1
或一步到位
export my_var_name1=my_var_value删除局部环境变量
unset my_var_name1我认为,只有读环境变量值的时候,才需要在变量名字的左边添加美元($)符号,其他情况,不需要使用$符号几个默认Shell环境变量
当前用户的主目录
HOME冒号分隔的Shell查找命令的目录列表
PATHShell命令行界面的主提示符
PS1Shell命令行界面的次提示符
PS2冒号分隔的目录列表,作为cd命令的搜索路径
CDPATH几个bash Shell环境变量
版本号
BASH_VERSION当前bash进程的PID
BASHPID保存shell历史记录列表的文件名(默认是.bash_history)
HISTFILE最多在历史文件中存多少行
HISTFILESIZE最多在历史文件中存多少条命令
HISTSIZE当前主机名称
HOSTNAME当前执行的脚本行号
LINENO自从Shell启动到现在的秒数;若对其赋值,将重置计数器
SECONDSShell的级别;每次启动一个新的bash shell,该值+1
SHLVLbash Shell创建临时文件的目录名
TMPDIR当前用户的真实用户ID
UID启动bash Shell有3种方式:
1、登陆时当做默认[登陆Shell]
2、作为非登录Shell的[交互式Shell]
3、作为运行脚本的[非交互Shell]当你登录Linux系统时,bash shell会作为登录Shell启动。登录Shell会依次从4个不同的启动文件里读取命令:
1、/etc/profile
2、$HOME/.bash_profile
3、$HOME/.bash_login
4、$HOME/.profile
其中/etc/profile是系统上默认的bash shell的主启动文件,系统上的每个用户登录时都会执行这个启动文件。
另外3个是用户专有的(大多数Linux发行版只用这3个文件中的一个),可以根据每个用户的具体需求定制。当你在命令行提示符下敲入bash启动,那你启动的是交互式Shell,而不是登录Shell。交互式Shell会运行这个启动文件
~/.bashrc
而这个启动文件默认(但不保证)会运行/etc/bashrc文件系统执行Shell脚本时用的是非交互式Shell,会运行BASH_ENV环境变量里定义的脚本文件要给某个环境变量设置多个值,可以把值放在括号里,值与值用空格( ) 间隔
my_arr_var=(val1 val2 val3)显示0号值
echo ${my_arr_var[0]}显示整个数组的值
echo ${my_arr_var[*]}设置2号值
my_arr_var[2]=val_three删除1号值
unset my_arr_var[1]
此时若显示这个数组
echo ${my_arr_var[*]} 为val1 val_three
但是单独显示1号值
echo ${my_arr_var[1]} 为空白字符串删除整个数组
unset my_arr_var查看已有的命令别名列表
alias -p建议在~/.bashrc里创建命令别名####第6章####
root账号是Linux系统的管理员,通常分配给它的UID是0Linux为系统账户预留了500以下的UID值,所以,大多数Linux系统会将500作为第一个可用UID分配给普通账户Linux系统将用户密码保存在/etc/shadow文件中,且只有root用户才能访问这个文件,相比之下,/etc/passwd文件是个标准文本文件,任何人都可以手动修改它查看Linux系统在创建用户时使用的各种默认值
/usr/sbin/useradd -D添加账户,并创建用户的HOME目录
useradd -m test
注意,useradd默认不创建用户的HOME目录删除账户
userdel
注意,userdel默认只删除/etc/passwd文件中的用户信息,而不会删除系统中属于该账户的任何文件。如果使用-r参数,就会删除该用户的HOME目录以及mail目录
userdel -r test修改用户账户的字段,并可以指定主要组以及附加组的所属关系。它用来修改/etc/passwd的大部分字段,而且参数大部分与useradd相同修改用户密码
passwd test
注意,-e选项,可以强制用户下次登录的时候修改密码批量修改用户密码,chpasswd可以从标准输入或文件读入登录名和密码对(由冒号分割,即userid1:passwd1)
chpasswd < users.txt修改默认的用户登录shell
chsh -s /bin/csh test修改/etc/passwd文件的备注(finger)字段
chfn test
注意,备注字段主要由finger命令读取并显示
finger testchage可以修改账户的有效期/etc/group保存系统上用到的每个组的信息,该文件有4个字段,从左往右依次是:组名,组密码,GID,属于改组的用户列表系统账户组,通常分配低于500的GID值;普通用户组的GID从500开始分配。
注意,当一个用户在/etc/passwd文件中指定某个组作为默认组时,用户账户不会作为该组的成员再次出现在/etc/group文件中!所以,/etc/group文件中会有一些组,没有任何成员创建新组
/usr/sbin/groupadd group_name_1添加组成员
/usr/sbin/usermod -G group_name_1 user_1
注意,如果更改了已登录系统账户的组关系,该用户必须登出系统后重新登录,更改才能生效。还有,usermod如果使用了-g参数,指定的组名会替换该账户的默认组。-G参数会将该账户添加到指定的组中,不会影响默认组groupmod可以修改已有组的GID(-g参数)或组名(-n参数)
/usr/sbin/groupmod -n group_name_old group_name_newls -l 显示结果的第一个字符:
- => 文件
d => 目录
l => 链接
c => 字符型设备
b => 块设备
n => 网络设备之后的3组三字符码:
- => 没有权限
r => 可读
w => 可写
x => 可执行3组三字码分别对应对象的3个安全级别:
属主(User), 属组(Group),系统其他用户(Others)umask值为掩码,用于屏蔽掉不想授予该安全级别的权限。新创建的文件或目录的权限,会从文件或目录的全权限(文件为666,目录为777)中减掉umask的值umask值通常会在/etc/profile启动文件中设置设置
umask 026显示umask值
umask修改文件访问权限语法
chmod [ugoa][+-=][Xstugo]给test1文件的属主(User)添加执行权限(eXecute)
chmod u+X test1chmod的+X ,这个大写的X是指如果目标文件是可执行文件或者目录文件,则加x属性,否则不改变x权限位. 这里对“可执行文件”的定义是:这个文件至少已经有一个 x,不管是谁的给test1文件的属主读、写、执行权限,属组读、写权限,其他用户取消一切权限
chmod 760 test1改变文件的属主和属组
chown user1.group1 file1仅改变文件的属主
chown user1 file1仅改变文件的属组
chown .group1 file1只有root账户可以修改属主;任何账户都可以把一个属于自己组的文件的属组,修改到属于自己的另一个组里使用chgrp修改文件或目录的属组
chgrp group_name_1 file1####第7章####
ext文件系统采用成为索引节点的系统来存放虚拟目录中所存储文件的信息。索引节点系统在每个物理设备中创建一个单独的表(称为索引节点表)来存储这些文件的信息。存储在虚拟目录中的每一个文件在索引节点中表中都有一个条目。条目名称的扩展部分来自其跟踪的每个文件的额外数据,包括:文件名、文件大小、文件属主、文件属组、文件的访问权限、指向存有文件数据的每个磁盘块的指针。Linux通过唯一数值(称作索引节点号)来引用节点表中的每个索引节点,这个值是创建文件的时候由文件系统分配的。文件系统通过索引节点号,而不是文件全名及路径来标示文件。
ext文件系统文件大小不能超过2GBext2文件系统文件大小最大可以是2TB,后期版本中可以是32TB
ext2文件系统通过按组分配磁盘块来减轻碎片化。通过将数据块分组,文件系统不需要为了数据块查找整个物理设备来读取文件。ext3给每个存储设备增加了一个日志文件。但是该文件系统仍然无法恢复误删的文件,它没有任何内建的数据压缩功能(虽然有个需要独立安装的补丁支持这个功能),ext3文件系统也不支持加密文件。ext4文件系统除了支持数据压缩和加密外,还支持一个叫区段(extent)的特性,可以在索引节点表中节省一些空间。对于较早期的IDE硬盘,Linux用/dev/hdx,其中x代表基于磁盘发现顺序的字母(a代表第一块物理磁盘,b代表第二块物理磁盘,以此类推)。对于较新的SATA和SCSI硬盘,Linux采用/dev/sdx,其中x代表硬盘发现顺序将sdc1格式化为ext4文件系统
sudo mkfs.ext4 /dev/sdc1挂载文件系统
sudo mount -t ext4 /dev/sdb1 /mnt/testing
注意,这种挂载文件系统的方法只会临时挂载该文件系统。当重启Linux系统时,文件系统不会自动挂载。要强制Linux在启动时自动挂载这个新文件系统,可以将文件系统谈驾到/etc/fstab文件中。fsck命令用来检查和修复任意类型的Linux文件系统。它使用/etc/fstab文件来自动决定挂载到系统上的存储设备的文件系统。当然也可以使用-t参数指定要检查的文件系统类型你只能在为挂载的文件系统上运行fsck命令。因为根文件系统含有所有核心Linux命令和日志文件,你不能在运行的系统上卸载它。这正是亲手体验Linux LiveCD的好时机。只需要用LiveCD启动系统就可以了,然后在根文件系统上运行fsck命令。####第10章####
在一行运行多个命令,只要用分号(;)隔开就好了
date; who
注意,一行的字符数不能超过255shell脚本的第一行必须指定要使用的shell,如使用bash运行该shell脚本:
#!/bin/bash在shell中井号(#)表示注释,不会被shell执行(除了以#!开头的第一行)有两种方法可以让shell找到用户编写的shell脚本:
1、将shell脚本文件所处的目录添加到PATH环境变量中
PATH=$PATH;/path/to/my_shell_file
2、在提示符中使用绝对或相对文件路径来引用shell脚本
./my_shell_file
或
/path/to/my_shell_file打印字符串
echo This is a test如果要打印单引号(')或双引号("),需要用反斜线(\)将其转义,或使用另一种引号将整个字符串包围
echo Let\'s see if this\'ll work
或
echo "Let's see if this'll work"
或
echo 'Rch says "scripting is easy"'echo默认打印完毕后会换行,可以使用-n参数阻止其换行我认为,关于单引号(')和双引号("):单引号里的东西,被认为是字符串;双引号里可以使用变量,也就是说,echo "the UID=$UID"将会把$UID替换为UID变量的值,这在单引号里是不会发生的,所以,如果在双引号里要打印美元符号($),需要将其转义,echo "The cost of the item is \$15"在脚本中可以定义用户变量,变量名字可以是字符、数字或下划线的组合,长度不得超过20个字符,且区分大小写。在脚本的整个生命周期里,shell脚本定义的变量会一直保持着它们的值,但在shell脚本完成时删除掉。当然了,export到全局的变量,不会被删反引号(`)里的文本会被当做shell命令执行
today=`date +%y%m%d`
date -d '10 minute'     # 当前时间+10分钟
date -d '10 minute ago' # 当前时间-10分钟
date +%Y%m%d            # 20160620大于号(>)用于输出重定向
who > my_output_file_name_1
注意,文件my_output_file_name_1会被覆盖!双大于号(>>)用于追加数据
date >> my_output_file_name_1
注意,文件my_output_file_name_1不会被覆盖小于号(<)用于输入重定向
wc < input_file_name_1
wc命令默认返回三个数字,分别代表:行数,词数,字节数内敛输入重定向(<<),像Ruby里的Here Documents
wc << my_mark_1
test string 1
test string 2
test string 3
my_mark_1
注意,你可以使用任何字符串的值来作为文本标记,但在数据的开始和结尾,必须一致!
也可使用<<<实现Here String,如:
# https://www.gnu.org/software/bash/manual/bash.html#Here-Strings
$ read a b c <<< $(echo 1 2 3)
$ echo $a $b $c
1 2 3管道将一个命令的输出重定向到另一个上:
command1 | command2管道上的命令会被Linux【同时】运行,在系统内部将它们连接起来。在第一个命令产生输出的同时,输出立即被送给第二个命令,传输数据不会用到任何中间文件或缓冲区域。计算1+5
expr 1 + 5计算5*2
expr 5 \* 2
注意星号(*)需要被转义使用方括号计算
$[1 + 5]
$[5 * 2]
$[2 * (3 + 4)]expr和$[]只支持整数,不支持浮点数(结果中的浮点数会被截断)bc支持浮点数和变量
bc -q
scale=4
3.44/5
运行bc,设置小数位数为4。-p参数可以跳过很长的欢迎词条$?保存了上个执行的命令的退出状态码
0   => 成功
1   => 通用未知错误
126 => 命令不可执行
127 => 没找到命令
130 => 命令通过Ctrl + C 终止exit用于退出脚本并指定退出码
exit 5退出码只能是[0 ~ 255],超过的部分将被截断(&0xFF)####第11章####
if语法
if command
thencommands
fi
或
if command; thencommands
fibash shell的if语句会运行if行定义的那个命令。如果该命令的退出状态码是0, 位于then部分的命令就会被执行。如果该命令的退出状态码是其他什么值,那then部分的命令就不会被执行,bash shell 会继续执行脚本中的下一个命令。
+--------------------------------------------+
|#!/bin/bash                                 |
|#testing a bad command                      |
|if asdfg                                    |
|then                                        |
|  echo "it did not work"                    |
|fi                                          |
|echo "we are outside of the if statement"   |
+--------------------------------------------+
|xxx: line3: asdfg: command not found        |
|we are outside of the if statement          |
+--------------------------------------------++----------------------------------------------+
|#!/bin/bash                                   |
|#testing multiple commands in the then section|
|testuser=rich                                 |
|if grep $testuser /etc/passwd                 |
|then                                          |
|  echo The bash files for user $testuser are: |
|  ls -a /home/$testuser/.b*                   |
|fi                                            |
+----------------------------------------------+if-then-else命令
if command
thencommands
elsecommands
fi当if语句中的命令返回退出状态码0时,then部分中的命令会被执行,跟普通的if-then语句一样。当if语句中的命令返回非零退出状态吗时,bash shell会执行else部分中的命令。嵌套if
if command1
thencommands
elif command2
thenmore commands
fitest命令
test condition把test命令用在if语句中
if test condition
thencommands
fitest命令的另一种形式
[ condition ]
注意,condition与中括号之间要有空格,否则报错把test命令用在if语句中
if [ condition ]
thencommands
fi
注意,if与中括号之间要有空格,否则报错test命令的数值比较功能
+----------+-----------------------+
|   比较   |         描述          |
+----------+-----------------------+
|n1 -eq n2 | 检查n1是否与n2相等    |
|n1 -ge n2 | 检查n1是否大于或等于n2|
|n1 -gt n2 | 检查n1是否大于n2      |
|n1 -le n2 | 检查n1是否小于或等于n2|
|n1 -lt n2 | 检查n1是否小于n2      |
|n1 -ne n2 | 检查n1是否不等于n2    |
+----------+-----------------------+if [ 10 -gt 5 ]
thenecho "10 > 5"
fitest命令的字符串比较功能
+-------------+------------------------+
|     比较    |          描述          |
+-------------+------------------------+
|str1  = str2 |检查str1是否和str2相等  |
|str1 != str2 |检查str1是否和str2不相等|
|str1  < str2 |检查str1是否比str2小    |
|str1  > str2 |检查str1是否比str2大    |
|-n str1      |检查str1的长度是否非0   |
|-z str1      |检查str1的长度是否为0   |
+-------------+------------------------++------------------------------------+
|#!/bin/bash                         |
|# testing string comparisions       |
|                                    |
|val1=baseball                       |
|val2=hockey                         |
|                                    |
|if [ $val1 \> $val2 ]; then         |
|  echo "$val1 is greater than $val2"|
|else                                |
|  echo "$val1 is less than $val2"   |
|fi                                  |
+------------------------------------+注意,test命令在比较字符串时,根据ASCII顺序,大写字母比小写字母的ASCII值小。而sort命令,使用系统本地化语言设置中定义的排序顺序,对于英语,本地化设置指定了在排序中小写字母出现在大些字母前。test命令的文件比较功能
+----------+----------------------------------+
|  比较    |         描述                      |
+----------+----------------------------------+
|-d file   |检查file是否存在并是一个目录          |
|-e file   |检查file是否存在                    |
|-f file   |检查file是否存在并是一个文件          |
|-r file   |检查file是否存在并可读               |
|-s file   |检查file是否存在并非空               |
|-w file   |检查file是否存在并可写               |
|-x file   |检查file是否存在并可执行             |
|-O file   |检查file是否存在并归当前用户所有       |
|-G file   |检查file是否存在并且默认组与当前用户相同|
|file1 -nt |检查file1是否file2 比file2新        |
|file1 -ot |检查file1是否file2 比file2旧        |
+----------+----------------------------------++-----------------------------------------------------+
|#!/bin/bash                                          |
|#look before you leap                                |
|if [ -d $HOME ]; then                                |
|  echo "Your HOME directory exists"                  |
|  cd $HOME                                           |
|  ls -a                                              |
|else                                                 |
|  echo "There is a problem with your HOME directory" |
|fi                                                   |
+-----------------------------------------------------+if-then语句允许你使用布尔逻辑来组合测试。有两种布尔运算符可用:
1. [ condition1 ] && [ condition2 ]
2. [ condition1 ] || [ condition2 ]双圆括号命令允许你讲高级数学表达式放入比较中
((expression))双圆括号命令符号
+------+--------+
| 符号 |   描述 |
+------+--------+
|val++ |后增    |
|val-- |后减    |
|++val |先增    |
|--val |先减    |
|!     |逻辑求反|
|~     |按位取反|
|**    |幂运算  |
|<<    |左移位  |
|>>    |右移位  |
|&     |按位与  |
||     |按位或  |
|&&    |逻辑与  |
|||    |逻辑或  |
+------+--------++-------------------------------------+
|#!/bin/bash                          |
|# using double parenthesis           |
|val1=10                              |
|                                     |
|if (($val1**2>90)); then             |
|  ((val2=$val1**2))                  |
|  echo "The square of $val1 is $val2"|
|fi                                   |
+-------------------------------------+
注意,双圆括号里不需要转义大于号(>)双方括号命令支持字符串的模式匹配
+---------------------------------+
|#!/bin/bash                      |
|# using pattern matching         |
|                                 |
|if [[ $USER == r* ]];then        |
|  echo "Hello $USER"             |
|else                             |
|  echo "Sorry, I do not know you"|
|fi                               |
+---------------------------------+
注意,中括号里的空格,一个都不能少,否则报错!case语法
case variable inpattern1 | pattern2) commands1;;pattern3) commands2;; # 如果commands2在下一行, 则此处要有冒号(:), 表示空操作(noop)*) default commands;;
esac
或
show_usage(){case $1 in'start'):# 注意此处的冒号(:)echo 'start';;*):echo '*'$1;;esac
}####第12章####
for命令的基本格式
for var in list
docommands
done
或
for var in list; docommands
done读取列表中的值
for test in Alabama Alaska Arizona Arkansas California Colorado
doecho The next state is $test
done从变量中读取列表
list="Alabama Alaska Arizona Arkansas Colorado"
list=$list" Connecticut"
for state in $list
doecho "Have you ever visited $state?"
done从命令读取值
file="states"
for state in `cat $file`
doecho "Visit beautiful $state"
doneIFS(internal field separator)环境变量定义了bash shell 用作字段分隔符的一系列字符。默认情况下,bash shell会将下列字符当做字段分隔符:
1. 空格
2. 制表符
3. 换行符修改IFS,使其只能识别换行符
IFS=$'\n'修改IFS,使其将换行符、冒号、分号和双引号作为字段分隔符
IFS=$'\n:;"'IFS一般在修改之前,需要备份一下,然后再恢复它的值打印IFS
echo $IFS|od -b用通配符读取目录
for file in /home/rich/test/*
doif [ -d "$file" ]thenecho "$file is a directory"elif [ -f "$file" ]thenecho "$file is a file"fi
done
注意,由于Linux中目录名和文件名中允许包含空格,所以$file变量需要用双引号圈起来,如果不这么做,遇到含有空格的目录名和文件名时,会报错。C语言风格的for命令
for ((i=1;i<=10;i++))
doecho "The next number is $i"
done使用多个变量
for ((a=1,b=10;a<=10;a++,b--))
doecho "$a - $b"
donewhile循环
val1=10
while [ $val1 -gt 0 ]
doecho $val1val1=$[ $val1 - 1 ]
done使用多个测试命令
val=2
while echo $val
[ $val -gt 0 ]
doecho "This is inside the loop"
done
运行结果
2
This is inside the loop
1
This is inside the loop
0
This is inside the loop
-1
注意,每个测试命令都是在单独的一行上,且只有最后一个测试命令的退出状态码会被用来决定什么时候结束循环,非零的退出状态码,会终止while循环until命令与while命令相反,0退出状态码会导致until循环终止嵌套循环
for ((a=1;a<=3;a++))
doecho "Starting loop $a:"for ((b=1;b<=3;b++))doecho "  Inside loop: $b"done
donebreak和continue命令用于跳出和提早循环内部的命令。两者都可以接受单个命令行参数
break n
和
continue n
其中n表示需要跳出或提早结束的循环层数,默认是1可以将循环的输出Pipe或Redirect,可以在done命令之后添加一个处理命令
for file in /home/rich*
doif [ -d "$file" ]thenecho "$file is a directory"elifecho "$file is a file"fi
done > output.txt也可以使用Pipe
for state in "North Dakota" Connecticut Illinois Alabama Tennessee
doecho "$state is the next place to go"
done | sort
####第13章####
bash shell会将一些成为位置参数(positional parameter)的特殊变量分配给命令行输入的所有参数,其中会包括shell执行的程序的名字。位置参数变量是标准的数字
$0    => 程序名
$1    => 第1个参数
$2    => 第2个参数...
$9    => 第9个参数
${10} => 第10个参数
${11} => 第11个参数
注意,当传给$0变量的真实字符串是整个脚本的路径时,程序中就会使用整个路径,而不仅仅是程序名。这时候可以使用basename的命令,从$0中提取程序名,而不包括路径
name=`basename $0`建议在使用参数前,检查参数是否被正确传入
if [ -n "$1" ]
thenecho Hello $1, glad to meet you
elseecho "Sorry, you did not identify yourself."
fi$#特殊变量含有脚本运行时就有的命令行参数的个数脚本的最后一个参数是
${!#}
而不是
${$#}
因为在花括号内不能使用美元符$*变量会将所有参数当成单个参数,$@变量会单独处理每个参数
#!/bin/bash
#testing $* and $@
count=1
for param in "$*"
doecho "\$* Parameter #$count = $param"count=$[ $count + 1 ]
done
count=1
for param in "$@"
doecho "\$@ Parameter #$count = $param"count=$[ $count + 1 ]
done
按如下方式调用
./test12 rich barbara katie jessica
输出为
$* Parameter #1 = rich barbara katie jessica
$@ Parameter #1 = rich
$@ Parameter #1 = barbara
$@ Parameter #1 = katie
$@ Parameter #1 = jessica使用shift命令,默认情况下会将每个参数变量减一。所以,变量$3的值会移到$2,变量$2的值会移到$1,而变量$1的值会被删除(注意,变量$0的值,也就是程序名,不会改变)一旦参数被shift移除后,它的值会被丢掉并且无法恢复getopt命令可以接受一些列任意形式的命令行选项和参数,并自动将它们转换成适当的格式。它的命令格式如下:
getopt optsring options parameters
其中,optstring是这个过程的关键所在。它定义了命令行有效的选项字母,还定义了哪些选项字母需要参数值。定义a、b、c、d四个有效参数字母,其中选项字母b需要一个参数值
getopt ab:cd -a -b test1 -cd test2 test3
输出为
-a -b test1 -c -d -- test2 test3
注意,它自动将-cd选项分成两个单独的选项,并插入双破折线来区分开行中的额外参数如果使用了一个不在optstring中的选项,默认情况下,getopt命令会产生一条错误信息。如果想忽略这条错误信息,可以在命令后加-q选项
getopt -q ab:cd -a -b test1 -cde test2 test3
输出为
-a -b test -c -d -- test2 test3set命令使用双破折线选项,可以将命令行参数替换成set命令的命令行的值
set -- `getopt -q ab:cd "$@"`
现在原始的命令行参数变量的值会被getopt命令的输出替换,而getopt已经为我们格式化好了命令行参数注意,getopt命令并不擅长处理带空格的参数值。它会将空格当做参数分隔符,而不是根据双引号将二者当做一个参数。不过,可以使用getopts可以解决这个问题。getopts命令的格式如下:
getopts optstring variable
有效的选项字母都会列在optstring中,如果选项字母要求有个参数值,就加一个冒号(:)。如果要去掉错误小心,可以在optstring的左边加一个冒号(:)。getopts会将当前参数保存在命令行中定义的variable中。getopts命令会用到2个环境变量。如果选项需要跟一个参数值,OPTARG环境变量会保存这个值;如果要获知getopts正在处理参数列表的参数的位置,那么OPTIND环境变量会保存这个值。
#!/bin/bash
# simple demonstration of the getopts command
while getopts :ab:c opt
docase "$opt" ina) echo 'Found a';;b) echo "Found b, with value $OPTARG";;c) echo 'Found c';;*) echo 'Unknown option: $opt';;esac
done
按如下方式调用
./test19 -ab test1 -cd
输出为
Found a
Found b, with value test1
Found c
Unknown option: ?
注意,getopts命令解析命令行选项时,它会移除开头的单破折线,所以在case定义中不用单破折线。对于未定义的选项,统一被输出成问号(?)getopts处理每个选项时,它会将OPTIND环境变量值+1。getopts处理完所有参数后,它将退出并返回一个 >0 的退出状态码。read命令接受从标准输入(键盘)或另一个文件描述符的输入
echo -n "Enter your name:"
read name
echo "Hello $name~"可以使用-p参数,使用read输出提示语句
read -p 'Enter your name:' name如果read命令行中未指定变量,则read会将读到的数据保存在环境变量REPLY中-t参数可以给read命令设置等待输入的秒数,这个时间内,如果用户没有输入任何值,read命令将返回一个非0退出状态码
read -t 5 -p "Please enter your name:" name-n参数可以设置read命令读取几个字符后退出,这样用户在输入特定个数的字符后,不必按Enter键了
read -n1 -t 5 -p "Do you want to contnue [Y/N]?" name-s参数可以阻止将传给read命令的数据显示在显示器上(实际上,数据会被显示,只是read命令会将文本颜色设置成跟背景色一样),特别适合用作密码输入
# The -r prevents the special treatment of \, since read normally accepts that as a line-continuation when it's at the end of a line.
printf 'Enter [y/n] : '
read -r opt从文件中读取
cat my_file_1 | while read line
docommands
done
####第14章####
Linux的标准文件描述符
0 => STDIN  => 标准输入
1 => STDOUT => 标准输出
2 => STDERR => 标准错误在使用输入重定向符号(<)时,Linux会用重定向指定的文件来替换标准输入文件描述符,它会读取文件并提取数据,就如同它是键盘上键入的
cat < my_file_1.txt通过输出重定向符号(>)时,通常显示到显示器的所有输出会被shell重定向到指定的文件中,该文件会被覆盖。若使用>>符号,则文件不会被覆盖,输出的内容会被追加到文件原有的内容上
ls -l > test2
who >> test2默认情况下,STDERR文件描述符会和STDOUT文件描述符指向相同的地方,但是重定向STDOUT后,并不会自动重定向STDERR,所以应该单独重定向STDERR
ls -al badfile 2> test4
注意,2>之间不能有空格,否则不会工作!可以将STDOUT和STDERR分别重定向到不同的文件
ls -al test test2 test3 badtest 2> test6 1>test7
把STDOUT重定向到test7中,STDERR重定向到test6中也可以把STDOUT和STDERR重定向到同一个文件中,这时候要使用特殊重定向符号&>
ls a b c d &> a.txt
cat a.txt
把STDOUT和STDERR都重定向到test7中
输出为
ls: 无法访问a: No such file or directory
ls: 无法访问c: No such file or directory
ls: 无法访问d: No such file or directory
b
bash shell会自动给STDERR分配较STDOUT更高的优先级,所以STDERR输出的信息会出现在前几条在重定向到文件描述符时,必须在文件描述符数字之前加一个and符(&)
echo "This is an error message" >&2你可以用exec命令告诉shell在脚本执行期间重定向某个特定文件描述符。exec命令会启动一个新的shell,并将STDOUT文件描述符重定向
#!/bin/bash
exec 1>testout
echo "This is a test of redirecting all output"
echo "from a script to another file."
echo "without having to redirect every individual line"exec命令也允许你将STDIN重定向到Linux系统上的文件中
exec 0<testfileshell中最多可以有9个打开的文件描述符。其中6个文件描述符会从3排到8,并且当做输入或输出重定向都行将前两行文本输出到文件,最后一行文本输出到屏幕
exec 3>&1
exec 1>test14out
echo "This should store in the output file"
echo "along with this line."
exec 1>&3
echo "Now things should be back to normal"
注意,这是在脚本中临时将输出重定向,然后再将输出恢复到通常设置的通用方法。先暂存输出文件描述符,再重定向输出文件描述符,最后恢复输出文件描述符可以打开单个文件描述符作为输入和输出。你可以用同一个文件描述符来从文件中读取数据,并将数据写到同一个文件中
exec 3<>testfile
read line <&3
echo "Read: $line"
echo "This is a test line" >&3
假设testfile原有的内容为:
This is the first line.
This is the second line.
This is the third line.
那么脚本运行后,屏幕的输出为:
Read: This is the first line.
testfile的内容为:
This is the first line.
This is a test line
ine.
This is the third line.
也就是说,脚本向文件中写入数据时,它会从文件指针所处的位置开始。read命令读取了第一行数据,所以它会让文件指针指向第二行数据的第一个字符。在echo语句将数据输出到文件时,它会将数据放在文件指针的当前位置,覆盖任何位置的任何数据。要关闭文件描述符,可以将它重定向到特殊符号&-
exec 3>&-
一旦关闭了文件描述符,你就不能在脚本中向它写入任何数据了,否则shell会生成错误信息。在关闭文件描述符时还要注意另一件事,如果后面你在脚本中打开了同一个输出文件,shell会用一个新文件替换已有的文件。这意味着如果你要输出任何数据,它将会覆盖已有的文件,即每次重定向文件描述符到一个文件,shell都会重新打开该文件。lsof命令会列出整个Linux系统打开的所有文件描述符。通常Linux会隐藏该命令,在Fedora Linux上,该命令位于/usr/sbin/lsof。要用普通账户运行它,就必须通过全路径名来引用它当前进程对0,1,2文件描述符的使用情况,其中-a表示对其他两个选项的结果执行布尔AND运算;-p指定进程PID,-d指定要显示的文件描述符
/usr/sbin/lsof -a -p $$ -d 0,1,2找出占用3003和15718端口的进程的PID
pids=`lsof -i :3003 -i :15718|awk 'NR>=2{print $2}'`
或
pids=`lsof -i :300,15718|awk 'NR>=2{print $2}'`lsof显示端口号,而不是人类可阅读的端口名称 http://blog.sina.com.cn/s/blog_e4c513fe0101nuj0.html
lsof -P -i|less# 列出打开了file1或者(OR)file2的打开情况; 如果file1是目录, 那么列出直接打开这个目录的打开情况; 如果file1是个挂载点, 那么递归列出打开该挂载点下的各个文件的打开情况
lsof file1 file2 # (非递归)列出打开直接位于dir1目录下的文件的打开情况
lsof +d dir1# (递归)列出打开dir1目录下的文件的打开情况
lsof +D dir1# lsof的-c参数可以显示以某些字符开头的command打开的文件, -a参数表示AND(默认OR), 最后可以加多个文件参数(这些文件之间只能是OR的关系)
# uniq的-d参数仅显示重复的行, -u仅显示不重复的行, -c参数在输出行前面加上每行在输入文件中出现的次数
# 下面这条命令会打印同时打开了'./txt'和'./data'文件的tail命令的pid, 如果没有, 则什么都不会输出
lsof -c tail -a "./txt" "./data"|awk 'NR>1{print $2}'|uniq -d# 列出messagebus用户的文件打开情况
lsof -u messagebus# 列出所有 tcp、udp 连接
lsof -i tcp;
lsof -i udp;# 列出目前连接主机nf5260i5-td上端口为:20,21,80相关的所有文件信息,且每隔3秒重复执行
lsof -i @nf5260i5-td:20,21,80 -r 3# 列出192.168.1.91网的文件打开情况
lsof -i@192.168.1.91# 杀掉某个用户所有打开的文件、设备, -t参数仅输出pid, 可以供kill使用
kill -9 `lsof -t -u lakshmanan`在linux系统上null将文件的标准位置是/dev/null。你重定向到该位置的任何数据都会被丢掉,不会被显示
ls -al > /dev/nullLinux使用/tmp目录来存放不需要一直保留的文件。大多数Linux发行版配置了系统在启动时自动删除/tmp目录的所有文件。系统上的任何用户都有权限在/tmp目录中读写mktemp命令用于在当前路径创建一个名字唯一的临时文件,这个文件不使用默认的umask值。它会将文件的读写权限分配给文件的属主,并将你设置成文件的属主mktemp命令会用3个字符码替换3个XXX,从而保证文件名在目录中是唯一的
mktemp my_test_file.XXX
注意,本例中,mktemp的输出,是文件名-t选项会强制mktemp命令在系统的临时目录中创建临时文件
mktemp -t my_test_file.XXX
注意,本例中,mktemp的输出是临时文件的全路径,而不只是文件名,这是由于使用了-t参数的缘故-d选项用于在当前目录下,创建临时目录
mktemp -d my_test_dir.XXX当然,可以将-d和-t参数可以同时使用,用于在系统的临时目录下创建临时目录
mktemp -t -d my_test_dir.XXXtee命令相当于管道的一个T型接头。它将从STDIN过来的数据同时发给两个目的地。一个目的地是STDOUT,另一个目的地是tee命令所指定的文件名
date | tee my_test_file_1
注意,默认情况下tee在每次使用时会覆盖输出文件的内容,但是可以使用-a参数,用于向现有文件中追加新的内容
####第15章####
默认情况下,bash shell会忽略收到的任何SIGQUIT(3)和SIGTERM(5)信号,但是bash shell会处理收到的SIGHUP(1)和SIGINT(2)信号键盘上Ctrl+C会生成SIGINT信号;Ctrl+Z会生成SIGTSTP信号,停止shell中运行的任何进程,停止(SIGTSTP)一个进程和终止(SIGHUP)一个进程不同,停止进程会让程序继续保留在内存中,并能从上次停止的位置继续运行。trap命令允许你来指定shell脚本要观察哪些Linux信号并从shell中拦截。如果脚本收到了trap命令中列出的信号,它会阻止该信号被shell处理,而在本地处理。
#!/bin/bash
trap "echo ' Sorry! I have trapped Ctrl-C'" SIGINT SIGTERM
echo "First line"
sleep 60
echo "Second line"
echo "End"
该脚本在运行期间,会忽略SIGINT和SIGTERM信号,也就是说,键盘上的Ctrl+C命令将不会终止该脚本!#!/bin/bash
trap "echo bye~" EXIT
echo "First line"
sleep 60
echo "Second line"
echo "End"
该脚本在退出时,会输出"bye~",不管是脚本正常运行的退出还是键盘输入的Ctrl+C移除对EXIT信号的捕获,使用trap命令,后跟单破折线,再跟需要移除的(一组)信号
trap - EXIT要在命令行界面下,以后台模式运行shell脚本,只要在命令偶加一个&符就可以了
./test1 &显示后台运行的命令
jobs
注意,该命令仅显示job号,不显示PID显示后台运行命令,并且显示对应的PID
jobs -l把job号为1的后台命令转到前台运行
fg 1把job号为1的命令转到后台运行。前台命令在运行的时候,可以使用Ctrl+Z,使其停止,此时使用jobs命令可以看到它的job号
bg 1向job号为1的命令发送SIGTERM命令
kill %1nohup命令运行了另外一个命令来阻断所有发送给给进程的SIGHUP信号。这会在退出终端会话时阻止进程退出。
nohup ./test1 &
在test1运行过程中,即使退出了终端,test1也不会退出!由于nohup命令从终端解除进程的关联,进程会丢掉到STDOUT和STDERR的连接。为了保存该命令产生的输出,nohup命令会自动将STDOUT和STDERR的消息重定向到一个名为nohup.out的文件中。如果nohup运行了该目录下的多个命令,那么这些命令的输出都会被追加到同一个nohup.out文件中,这会让你凌乱$$变量代表当前进程的PIDjobs参数
-l => 列出PID和作业号
-n => 列出上次shell发出的通知后改变了状态的作业
-p => 列出PID
-r => 列出运行中的作业
-s => 列出已停止的作业调度优先级从-20(最高优先级)到+20(最低优先级),默认是0nice命令运行你在启动时调整一个命令的调度优先级
nice -n 10 ./test4 &renice允许你指定运行进程的PID来改变它的优先级
renice 10 -p 12345
注意,你只能对属于你的进程执行renice;你只能通过renice降低进程的优先级;root用户不受前两条的限制at命令允许指定Linux系统何时运行脚本。at命了会将作业提交到队列中,指定shell何时运行该作业at的守护进程atd会以后台模式运行,并检查作业队列来运行作业。atd会检查系统上的一个特殊目录(通常位于/var/spool/at)来获取at命令提交的作业。默认情况下atd会每隔60s检查一下这个目录。at命令的基本格式
at [-f filename] time
默认情况下,at命令会将STDIN的输入放到队列中。但是可以用-f参数来指定读取命令(脚本文件)的文件名。可以指定时间、日期、时间增量。如果指定了一个已经过去的时间,at命令会在第二天的这个时间运行该作业。
at -f test_file1 12:00
列出at命令的任务队列
at -l
清空编号为1的at任务
at -d 1
清空全部at任务
at -l|awk '{print $1}'|xargs at -d针对不同优先级,存在26种不同的作业队列。作业队列通常用小写字母a-z来引用。字母序越高,优先级越低。可以使用-q参数指定不同的队列字母。/usr/bin/batch命令会调用at命令并将作业提交到b队列中at作业的STDOUT和STDERR是提交该作业的用户的E-mail。当作业完成时,屏幕上不会有任何输出,但系统生成了一封E-mail信息。如果脚本没有产生任何输出,默认情况下系统不会生成E-mail信息,但是可以通过at命令的-m参数来改变这种情况。atq用于列出正在等待的at作业atrm用于通过作业号,删除正在等待的at作业Linux系统使用cron程序来计划要定期执行的作业。cron会在后台运行并检查cron table,来获得计划执行的作业cron时间表格式如下:
min hour dayofmonth month dayofweek command
其中时间可以是特定值(如3)、值范围(如1~5)或通配符(*)可以使用一条date命令和if-then语句来检查明天的日期是不是01,从而设置cron在每个月的第一天指定某个命令
00 12 * * * if [ `date +%d -d tomorrow` = 01 ]; then; command# 每2小时检查一次240分钟前修改过的非*.tmp,非*.log,非*.tar.gz,名字格式为*T*的文件并删除之
0 */2 * * * root find /my_home ! -name '*.tmp' ! -name '*.log' ! -name '*.tar.gz' -name '*T*' -type f -mmin +240 -exec rm -rf {} \;列出cron table
crontab -l在编辑器中打开crontab
crontab -e/etc/crontab中的百分号(%)表示换行, 所以要使用反斜线(\)进行转义:
# http://blog.csdn.net/q279838089/article/details/41519441
* * * * * root echo -e "$(date +\%s) \t$RANDOM">>/root/sec_rand.txtcron有4个基本的目录:hourly、daily、monthly和weekly
ls /etc/cron.*ly
/etc/cron.daily目录下的脚本,会被按天执行; /etc/cron.hourly目录下的脚本,会被按小时执行; 以此类推
cron程序的唯一问题是它假定Linux系统时7X24小时运行的anacron程序只会处理位于cron目录的程序,比如/etc/cron.monthly。它用时间戳来决定作业是否在适当的计划间隔内运行过。每个cron目录都有一个时间戳文件,位于/var/spool/anacron。anacron程序有自己的用来检查作业目录的表(通常位于/etc/anacrontab),时间格式与crontab略有不同:
period delay identifier command
其中period的单位是day;delay单位是minute,用于指定系统启动多少minute后,anacron程序开始运行错过的脚本。anacron不运行位于/etc/cron.hourly的脚本,因为anacron程序不会处理执行的时间需求小于一天的脚本System V的init过程会读取/etc/inittab文件,该文件会列出系统的运行级别(run level)Linux运行级——基于Red Hat的发行版
0 => 关机
1 => 单用户模式
2 => 多用户模式,不支持网络
3 => 多用户模式,支持网络
4 => 可定义用户
5 => 多用户模式,支持网络和X Window会话
6 => 重启Linux运行级——基于Debian的发行版(如Ubuntu和Linux Mint)
0   => 关机
1   => 单用户模式
2~5 => 多用户模式,支持网络和X Window会话
6   => 重启
注意,Ubuntu的发行版没有/etc/inittab文件,需要用户自己创建有些发行版将开机脚本放到/etc/rc#.d目录,其中#代表运行级;有些采用/etc/init.d目录;还有些采用/etc/init.d/rc.d目录Upstart中,系统开机成为开机事件(startup event),它使用位于/etc/event.d或/etc/init目录下的文件来启动进程,具体取决于发行版和版本。Linux本地开机文件位置
Debian   => /etc/init.d/rc.local
Fedora   => /etc/rc.d/rc.local
Mandriva => /etc/rc.local
OpenSUSE => /etc/init.d/boot.local
Ubuntu   => /etc/rc.local
在这些文件中使用脚本时,要指定脚本的全路径
####第18章####
sed命令选项
-e script => 将script中指定的命令添加到运行的命令中
-f file   => 将file中指定的命令添加到运行的命令中
-n        => 不要为每个命令生成输出,等待print命令来输出把my_data1文件中的brown替换成green,dog替换成cat
sed -e 's/brown/green/; s/dog/cat/' my_data1
注意,这2个命令都可以作用到文件中的每行数据上。命令之间必须用分号分隔,并且在命令结尾和分号之间不能有空格。当然了,也可以把这2个命令分到2行上书写,这样就可以不使用分号分隔了使用script1文件中的命令来处理my_data1文件
sed -f script1 my_data1
其中script1文件的内容是
s/brown/green/
s/fox/elephant/
s/dog/cat/gawk会将如下变量分配给它在文本行中发现的每个数据段:
$0 => 整个文本行
$1 => 文本行的第一个数据段
$2 => 文本行的第二个数据段
...
$n => 文本行的第 n个数据段每个数据段在文本行中都是通过字段分隔符来划分的,gawk中默认的字段分隔符是任意的空白字符(如空格或制表符)可以使用-F来指定分隔符
gawk -F : '{print $1}' /etc/passwd要在命令行上的程序脚本中使用多个命令,只要在每条命令之间使用分号分隔即可
echo 'My name is Rich' | gawk '{$4="Christine"; print $0}'
输出为
My name is Christine当然了,也可以每行写一条命令,这样就可以不使用分号了从script2中读取命令
gawk -F : -f script2 /etc/passwd
其中script2的内容是
{print $1 "'s home directory is " $6}可以在gawk中定义变量
gawk -F : -f script3 /etc/passwd
其中script3的内容是
{
text = "'s home directory is "
print $1 text $6
}
注意,gawk中引用变量值时,并未像shell脚本一样使用美元符号gawk会在读取数据前,执行BEGIN关键字后面指定的程序脚本,在读完数据后会执行END关键字后面指定的程序脚本;可以使用FS变量,在gawk的脚本中指定字段分隔符
gawk 'BEGIN{print "The data4 File Contents:"; FS=":"} {print $0} END{print "This concludes the listing"}' data4awk可以把十六进制/科学计数法转成十进制数字
# http://blog.sina.com.cn/s/blog_67f37e760102uw4e.html
echo '123 0x123 2.14e+03'|awk -F ' ' '{printf("%d,%d,%lld\n", $1, $2, $3)}'sed替换命令的格式
sed 's/pattern/replacement/flags'
其中flags可以是以下4中值
1. 数字        => 表明新文本将替换第几(从1开始数)处模式匹配的地方
2. g           => 表明新文本将会替换所有已有文本出现的地方
3. p           => 表明原来行的内容要打印出来
4. w file_name => 将替换的结果写到文件中
数字和g,不能同时使用,否则报错;p和w file_name可以同时使用把第二个c替换成C并打印这一行
echo 'abccd' | sed -n 's/c/C/2p'
输出为
abcCd
注意,-n选项,可以阻止sed的默认输出,通常与p标记配合使用,使sed仅打印成功执行替换的行,不打印未替换的行,如
echo 'abccd' | sed -n 's/c/C/3p'
不输出任何内容,因为没有执行替换sed允许选择其他字符来作为替换命令中的字符串分隔符,如使用感叹号(!)作为字符串的分隔符,将/etc/passwd文件里的/bin/bash字符串替换为/bin/csh字符串
sed 's!/bin/bash!/bin/csh!' /etc/passwdsed支持2种形式的行寻址
1. 行的数字范围将第3~5     行的dog替换成cat:sed '3,5s/dog/cat/' my_file1将第3~最后一行的dog替换成cat:sed '3,$s/dog/cat/' my_file1将第10      行的dog替换成cat:sed '10s/dog/cat/' my_file12. 用文本模式来过滤出某行将含有有Bob的行开始(包含这一行)至含有Alice的行为止(包含这一行)的所有行中的dog替换成cat:sed '/Bob/,/Alice/s/dog/cat/' my_file1将第animal 行的dog替换成cat:sed '/animal/s/dog/cat/' my_file1一条sed的shell命令,可以执行多条sed内部的指令,这时候,如果多条sed内部指令在一行上书写,则需要使用分号(;)分隔这些指令;当然,也可以将这些指令写到一个大括号({})中,然后在大括号中的每行写一条指令
sed -n 's/a/A/gp; s/b/B/gp'
或
sed -n '{
s/a/A/gp
s/b/B/gp
}'sed中的d命令用于删除行,如删除第2~3行
sed '2,3d'
注意,sed并不会修改原始文件,你删除的行,只是从sed的输出结果中消失了,原始文件仍然包含那些“被删除的”行可以用两个文本模式来指定删除某个范围内的行:第一个模式会“打开”行删除功能,第二个模式会“关闭”行删除功能。sed编辑器会删除两个指定行之间的所有行(包括指定的行)
sed '/Bob/,/Alice/d' data6i命令会在指定的行前增加一个新行
a命令会在指定的行后增加一个新行
注意,两个命令不能同时使用,因为你必须指定是要将行增加到指定行的前边还是后边。新添加的行
echo 'Test Line 2' | sed 'i\
Test Line 1'
输出为
Test Line 1
Test Line 2如果要插入或附加多行文本,你必须对新文本中的每一行的末尾使用反斜线
echo 'Last Line' | sed 'i\
Line 1\
Line 2\
'c命令用于整行替换文本,如将第2行替换
echo 'Line 1\nLine 2\nLine 3' | sed '2c\
New Line 2
'
输出为
Line 1
New Line 2
Line 3可以在c命令中使用地址区间
echo 'Line 1\nLine 2\nLine 3\nLine 4' | sed '2,3c\
New Line
'
输出为
Line 1
New Line
Line 4
注意,这时会用1行文本,替换第2行和第3行,而不是逐一修改那两行文本!y命令是转换命令,是唯一可以处理单个字符的sed编辑器命令,格式如下:
[address]y/inchars/outchars/
转换命令会进行inchars和outchars值的一对一映射:inchars的第一个字符会呗转换为outchars中的第一个字符,第二个字符会被转换成outchars的第二个字符,以此类推。如果inchars和outchars的长度不同,则会报错!
echo '12345' | sed 'y/12345/一二三四五/'
输出为
一二三四五回顾打印
p => 打印文本
= => 打印行号
l => 打印可见的和不可见的行,对于不可见的ASCII字符,会使用8进制前加一个反斜线或标准C风格的命名法,比如\t代表制表符TABecho 'asdf' | sed -n 'p'
输出为
sadfecho 'asdf' | sed '='
输出为
1
asdfecho '\t' | sed 'l'
输出为
\t$
其中$代表行的结尾w命令用于向文件写入行。如将文本写入test.txt文件
echo 'abcd\nefgh' | sed 'w test.txt'
注意,运行sed编辑器的人,必须有该文件的写权限,否则报错r命令用于从文件读入行。不可以为r命令指定地址区间。r命令会将文件的内容附加到地址后面。如在第2行后附件test.txt的内容
cat > test.txt <<EOF
abcd
efgh
EOF
echo '123\n456\n789' | sed '2r test.txt'
输出为
123
456
abcd
efgh
789r命令一般与d命令组合使用,可以用一个文件中的内容替换另一个文件中的占位文本
cat > template.txt <<EOF
Would the following people:
LIST
please report to the office.
EOFcat > name_list.txt <<EOF
Bob
Alice
EOFsed '/LIST/{
r name_list.txt
d
}' template.txt
输出为
Would the following people:
Bob
Alice
please report to the office.
####第20章####
sed编辑器包含了三个可用来处理多行文本的特殊命令
N => 将数据流中的下一行加进来创建一个多行组来处理
D => 删除多行组中的第一行
P => 打印多行组中的第一行n命令会让sed跳过一行输入的文本。如删除第一行后面的空行,但是要保留最后一行前面的空行
cat > data1 <<EOF
This is the header line.This is a data line.This is the last line.
EOFsed '/header/{n;d}' data1
输出为
This is the header line.
This is a data line.This is the last line.N将数据流中的下一行加进来,创建一个多行组。相当于正则表达式里的单行模式(dot-all,点号可以匹配任意字符,包括换行符)
echo 'hello\nworld.' | sed -n 'N; s/hello.world/Hello World/p'
输出为
Hello World.D将删除多行组中的第一行
cat > data5 <<EOFThis is the header line.
This is the data line.This is the last line.
EOFsed '/^$/{N
/header/D
}' data5
输出为
This is the header line.
This is the data line.This is the last line.
注意,D命令会强制sed编辑器回到脚本的起始处,并在同一模式空间复制执行这些命令P命令只打印多行组的第一行
echo 'hello\nworld.' | sed -n 'N; P'
输出为
hellosed编辑器内部有模式空间(pattern space)和保持空间(hold space),前者是sed编辑器执行命令时保存待检验的文本的地方,后者用于临时保存一些行,有5个命令可以操作这2个空间
h => 模式空间复制到保持空间
H => 模式空间附加到保持空间
g => 保持空间复制到模式空间
G => 保持空间附加到模式空间
x => 交换模式空间和附加空间感叹号(!)命令是排除命令,即让原来会起作用的命令不起作用,如不打印含有header字符串的行
echo 'This is the header line.\nThis is the data line.\nThis is the last line.' | sed -n '/header/!p'
输出为
This is the data line.
This is the last line.使用模式空间、保持空间和排除命令,实现文本的按行翻转
cat > data2 <<EOF
This is the header line.
This is the first data line.
This is the second data line.
This is the last line.
EOF
sed -n '1!G; h; $p' data2
输出为
This is the last line.
This is the second data line.
This is the first data line.
This is the header line.据说Linux下有个叫tac的命令可以实现上述脚本的功能,即按行翻转打印文本,Mac下没有找到这个命令b命令用于跳转,命令格式如下
[address]b [label]
其中,address和label可选。如果不指定label,则会跳转到sed脚本的结尾label以冒号(:)开始,最多可以有7个字符,如
:label7t命令是测试命令,它会基于替换命令(s)的输出,跳转到一个标签,而不是基于地址跳转到一个标签。如果替换命令成功匹配并替换了一个模式,测试命令就会跳转到指定的标签;如果替换命令未能匹配指定的模式,测试命令就不会跳转。测试命令的格式是
[address]t [label]
跟跳转命令(b)一样,如果不指定标签,则t会跳转到sed脚本的末尾cat > data2 <<EOF
This is the header line.
This is the first data line.
This is the second data line.
This is the last line.
EOF
sed '{
s/first/matched/
t
s/This is the/No match on/
}' data2
输出为
No match on header line.
This is the matched data line.
No match on second data line.
No match on last line.与符号(&)用来替换命令中的匹配模式,不管预定义模式是什么文本,你都能用&符号在替换模式中引用它
echo 'The cat sleeps in his hat' |sed 's/.at/"&"/g'
输出为
The "cat" sleeps in his "hat"\1,\2,...,\n用于引用分组
echo "That furry cat is pretty" | sed 's/furry \(cat\)/\1/'
输出为
That cat is pretty一些常用的sed脚本
1. 行距加倍,默认情况下,sed的保持空间是一个空行
sed 'G' data2
1.1 行距加倍的时候,最后一行的末尾,不要添加空白行
sed '$!G' data2
2. 给文本添加行号,注意,要使用两个sed命令
sed '=' data2 | sed 'N; s/\n/ /'
3. 打印/etc/passwd的末尾10行文本。相当于tail -n 10 /etc/passwd
sed '{
:start
$q
N
11,$D
b start
}' /etc/passwd
原理在于,语句'N'会附加一行文本组成多行组,而'11,$D'会从第11行到最后一行之间,删除多行组的第一行,同时跳转到sed脚本的第1行,'b start'用于在第1行到第10行之间,跳转到sed脚本的第1行。该脚本相当于定义了一个滚动窗口(rolling window)。4. 删除连续的空白行
cat > data6 <<EOF
This is the first line.This is the second line.This is the third line.This is the fourth line.
EOFsed '/./,/^$/!d' data6
输出为
This is the first line.This is the second line.This is the third line.This is the fourth line.####第21章##gawk中$1表示数据行中的第一个数据字段,$2表示第二个数据字段,以此类推gawk数据字段和数据行变量
FIELDWIDTHS => 由空格分隔开的定义了每个数据字段确切宽度的一串数字
FS          => 输入字段分隔符
RS          => 输入行分隔符
OFS         => 输出字段分隔符
ORS         => 输出行分隔符默认情况下,OFS是一个空格,所以,如果你用命令
print $1,$2,$3
输出结果为
field1 field2 field3使用逗号(,)分隔输入,使用连字符(-)分隔输出字段
cat data1
gawk 'BEGIN{FS=","; OFS="-"} {print $1,$2,$3}' data1
输出为
data11,data12,data13
data21,data22,data23
data31,data32,data33data11-data12-data13
data21-data22-data23
data31-data32-data33一旦设置FIELDWIDTH变量,gawk将忽略FS变量,将只根据提供的字段宽度大小来计算字段
cat data1
gawk 'BEGIN{FIELDWIDTHS="3 5 2 5"}{print $1,$2,$3,$4}' data1
输出为
1005.3247596.37
11502.349194.00
05810.1298100.1100 5.324 75 96.37
115 -2.34 91 94.00
058 10.12 98 100.1
注意,一旦设定了FIELDWIDTHS变量的值,就不能改变了。这种方法不适用于变长的字段。gawk中几个常用的内建变量
ARGC     => 当前命令行参数个数
ARGIND   => 当前文件在ARGV中的位置
ARGV     => 包含命令行参数的数组
ENVIRON  => 当前shell环境变量及其值组成的关联数组(相当于Hash或者Map)
FILENAME => 用作gawk输入数据的数据文件的文件名
FNR      => 当前数据文件中的数据行数(File Number of Row)
NF       => 数据文件中的字段总数(Number of File)
NR       => 已处理的输入数据行数目(Number of Row)使用ARGC和ARGV。注意,程序脚本不算参数。ARGV的索引从0开始
gawk 'BEGIN{print ARGC,ARGV[0], ARGV[1]}' data1
输出为
2 gawk data1使用ENVIRON
gawk 'BEGIN{print ENVIRON["HOME"]; print ENVIRON["PATH"]}'
/home/Administrator
/usr/local/bin:/usr/bin使用NF
gawk 'BEGIN{FS=":"; OFS=":"}{print $1,$NF}' /etc/passwd
Administrator:/bin/bash
Guest:/bin/bash
__vmware_user__:/bin/bashFNR和NR有点类似,但是略有不同:FNR变量含有处理过的[当前数据文件]中的数据行总数;NR变量则含有处理过的[所有]数据行总数
cat > data1 <<EOF
> 1
> 2
> 3
> EOF
cat > data2 <<EOF
> one
> two
> three
> EOF
gawk '{print "FNR=",FNR,"NR=",NR}' data1 data2
输出为
FNR= 1 NR= 1
FNR= 2 NR= 2
FNR= 3 NR= 3
FNR= 1 NR= 4
FNR= 2 NR= 5
FNR= 3 NR= 6gawk自定义变量名可以使任意数目的字母、数字和下划线,但不能以数字开头,另外,gawk变量名区分大小写。gawk中可以使用命令行设定的参数
cat > data2 <<EOF
> one
> two
> three
> EOF
gawk '{print n}' n=1 data2
输出为
1
1
1
注意,在你设置了变量后,这个变量在BEGIN部分不可用!但是可以用-v命令来解决这个问题,还有,-v命令必须放在程序脚本之前:
gawk -v n=1 'BEGIN{print n}' data2
输出为
1数组变量赋值的格式如下:
var[index]=element
如
my_arrar['first']=1
my_arrar[2]      ='second'gawk支持标准数学运算符,其中包括+,-,*,/,**(幂运算),^(也是幂运算),%
$ gawk 'BEGIN{
> var[1]=34
> var[2]=3
> print var[1]**var[2]
> }'
输出为
39304使用for(var in array){...}的语法,可以遍历关联数组
gawk 'BEGIN{
>   my_array["a"]=1
>   my_array["g"]=2
>   my_array["m"]=3
>   my_array["u"]=4
>
>   for(idx in my_array){
> print "Index:",idx," - Value:",my_array[idx]
>   }
> }'
Index: u  - Value: 4
Index: m  - Value: 3
Index: a  - Value: 1
Index: g  - Value: 2
注意,索引值不会按照任何特定的顺序返回。使用delete关键字,可以删除数组元素
delete array_name[idx]
如
gawk 'BEGIN{
>    my_array["a"]=1
>    my_array["g"]=2
>    my_array["m"]=3
>    my_array["u"]=4
>
>    delete my_array["m"]
>    for(idx in my_array){
>  print "Index:",idx," - Value:",my_array[idx]
>    }
>  }'
Index: u  - Value: 4
Index: a  - Value: 1
Index: g  - Value: 2可以使用基本正则表达式(BRE)或扩展正则表达式(ERE)来过滤程序脚本作用在数据流的哪些行上,正则表达式必须出现在它要控制的程序脚本的左花括号前
gawk 'BEGIN{FS=","} /11/{print $1}' data1
将输出含有11的数据行的第1个数据字段可以使用波浪线(~),针对数据字段使用正则表达式匹配
gawk 'BEGIN{FS=","} $2 ~ /^data2/{print $0}' data1
将输出第二个数据字段以data2开头的数据行($0代表数据行)
也可以使用感叹号(!)来排除正则表达式的匹配,即对正则表达式的匹配结果取反
gawk -F: '$4==0/Administrator/{print $1,$NF}' /etc/passwd
输出为
Guest /bin/bash
__vmware_user__ /bin/bash也可以用关系运算符匹配字段
gawk -F: '$4==0{print $1}' /etc/passwd
打印第4个数据字段为0的行的第1个字段
还可以使用如下关系运算符
x == y
x <= y
x <  y
x >= y
x >  y
同时,这些运算符也可以用于比较文本数据。用于比较文本时,表达式需要完全匹配,而不是像正则表达式那样部分匹配!gawk支持if-else语句
cat > data1 <<EOF
> 1
> 30
> 5
> EOFgawk '{
>  if($1>20){
>    x=$1*2
>    print x
>  }
>  else{
>    x=$1/2
>    print x
>  }
> }' data1
输出为
0.5
60
2.5当然了,如果你不觉得恶心,也可以把if-else写在同一行上:
if(condition) statement1; else statement2
注意statement1后的分号gawk支持while语句,也支持break和continue
gawk 'BEGIN{> while(i<4 ){total=0
>   i=1
>   while(i<4){
>     total+=i
> if(i==2)
>   break
> i++
>   }
>   print total
> }'
输出为
3gawk支持do-while语句
gawk 'BEGIN{
>   total=0
>   i=1
>   do{
>     total+=1
> i++
>   }while(total<0)
>   print total
> }'
输出为
1
do-while语句总是保证循环体被执行至少1次gawk支持C风格的for循环
gawk 'BEGIN{
>   total=0
>   for(i=0;i<4;i++){
>     print i
>   }
> }'
输出为
0
1
2
3gawk中的printf函数与C语言里printf函数类似,支持格式化字符串
c => ASCII字符
d => 整数
i => 整数(跟d相同)
e => 科学计数法
g => 科学计数法或浮点数中较短的一种方式(可以记成general)
f => 浮点数
o => 八进制
x => 十六进制
X => 大写的十六进制
s => 字符串gawk '{printf "%-16s",$1}' data1
最小宽度为16个字符,左对齐,以字符串形式输出data1中每一行的第一个数据段gawk '{printf "%16.15s",$1}' data1
最小宽度为16个字符,最大宽度为15个字符,右对齐,以字符串形式输出data1中每一行的第一个数据段。如果这个数据段的长度超过最大宽度15,则截断之gawk '{printf "%5.1f",$1}' data1
最小宽度为5个字符,右对齐,以浮点数形式输出data1中每一行的第一个数据段,小数点后保留1位gawk提供了一些内建的数学函数:
int(x)   => x的整数部分,取靠近0的值,如5.6返回5,-5.6返回-5
exp(x)   => e的x次幂
rand()   => 0~1的随机小数
srand(x) => 以x为种子,生成随机数
sin(x)   => 正弦
cos(x)   => 余弦
log(x)   => 自然对数
sqrt(x) => x的平方根
注意,gawk能处理的数值大小有限定区间,溢出时会报错!gawk支持按位逻辑运算
and(v1, v2) => 按位与
or(v1, v2) => 按位或
xor(v1, v2) => 按位异或
compl(val) => 按位补
lshift(v1, count) => 左移count位
rshift(v1, count) => 右移count位gawk支持toupper(str),tolower(str),length([str]),split(str, a, [,r])等字符串函数gawk内建时间函数
mktime(datespec)            => 将一个按YYYY MM DD HH MM SS [DST]格式指定的日期转换成时间戳(从1970-01-01 00:00:00 UTC到现在的秒数)
strfime(format[,timestamp]) => 将当前时间的时间戳或timestamp(如果提供了的话)转化成用shell函数格式date()的格式化日期
system()                    => 返回当前时间的时间戳gawk支持自定义函数,但是要求这些自定义函数必须出现在所有代码块之前(包括BEGIN代码块)
gawk '
> function my_func(){
>   printf "%-16s - %s\n", $1, $4
> }
> BEGIN{FS=":"}
> {
>   my_func()
> }' /etc/passwd
输出为
Administrator    - 513
Guest            - 513
__vmware_user__  - 513一个awk的例子, print 函数输出的常量内容,必须放在双引号(")内,不能使用单引号('):
awk -F , '{print "select count(1) cnt, " $1 " network_id," "\"" $2 "\"" " tag from unknown_site_section where network_id = " $1 " and tag= " "\"" $2 "\" \n union all ";}' ~/Desktop/discard.csv >| ~/Desktop/discard.sql
awk -F \; '{print "select count(1) cnt, " $1 " network_id," "\"" $2 "\"" " tag from unknown_site_section where network_id = " $1 " and tag= " "\"" $2 "\" \n union all ";}' ~/Desktop/discard.csv >| ~/Desktop/discard.sql可以用自定义函数保存成文件,最终组织成函数库,使用的时候,用-f参数,在命令行加载这些函数库文件。但是,gawk不允许-f参数与内联脚本一起使用,不过,可以使用多个-f参数:
cat > my_lib <<EOF
> function my_func(){
>    printf "%-16s - %s\n", \$1, \$4
> }
> EOFcat > script1 <<EOF
> BEGIN{FS=":"}
> {
>   my_func()
> }
> EOFgawk -f my_lib -f script1 /etc/passwd
输出为
Administrator    - 513
Guest            - 513
__vmware_user__  - 513
变量说明:
$$
Shell本身的PID(ProcessID)
$!
Shell最后运行的后台Process的PID
$?
最后运行的命令的结束代码(返回值)
$-
使用Set命令设定的Flag一览
$*
所有参数列表。如"$*"用「"」括起来的情况、以"$1 $2 … $n"的形式输出所有参数。
$@
所有参数列表。如"$@"用「"」括起来的情况、以"$1" "$2" … "$n" 的形式输出所有参数。
$#
添加到Shell的参数个数
$0
Shell本身的文件名
$1~$n
添加到Shell的各参数值。$1是第1参数、$2是第2参数…。
我们先写一个简单的脚本,执行以后再解释各个变量的意义
# touch variable
# vi variable
脚本内容如下:
#!/bin/sh
echo "number:$#"
echo "scname:$0"
echo "first :$1"
echo "second:$2"
echo "argume:$@"
保存退出
赋予脚本执行权限
# chmod +x variable
执行脚本
# ./variable aa bb
number:2
scname:./variable
first: aa
second:bb
argume:aa bb
通过显示结果可以看到:
$# 是传给脚本的参数个数
$0 是脚本本身的名字
$1是传递给该shell脚本的第一个参数
$2是传递给该shell脚本的第二个参数
$@ 是传给脚本的所有参数的列表
strace my_process_idman 1 ls201. man命令可以查不同section的关键字:
Linux提供了丰富的帮助手册,当你需要查看某个命令的参数时不必到处上网查找,只要man一下即可。Linux的man手册共有以下几个章节:1、Standard commands (标准命令)2、System calls (系统调用)3、Library functions (库函数)4、Special devices (设备说明)5、File formats (文件格式)6、Games and toys (游戏和娱乐)7、Miscellaneous (杂项)8、Administrative Commands (管理员命令)    结论:
man 2 是获得系统(linux内核)调用的用法 ,
man 3 是获得标准库(标准C语言库、glibc)函数的文档;
平时用的是 man 1,linux标准命令的查询。
想了一下 cat <> file相当于cat 0<> file。之后在网上找到了如下信息:Use program <> file to open file for both reading and writing.I/O Redirection[j]<>filename
# Open file "filename" for reading and writing,
#+ and assign file descriptor "j" to it.
# If "filename" does not exist, create it.
# If file descriptor "j" is not specified, default to fd 0, stdin.
#
# An application of this is writing at a specified place in a file.
echo 1234567890 > File    # Write string to "File".
exec 3<> File             # Open "File" and assign fd 3 to it.
read -n 4 <&3             # Read only 4 characters.
echo -n . >&3             # Write a decimal point there.
exec 3>&-                 # Close fd 3.
cat File                  # ==> 1234.67890objdump hello 可以输出hello这个可执行文件的汇编段find可以加-exec参数,用于对find出来的结果,执行某些命令:
find . -name "*.a" -exec lipo -info "{}" \;
find . -name "*.a" -exec ls -l "{}" \;使用find和xargs创建文件夹,然后复制.h文件到相应的文件夹中:
find . -type d|xargs -I {} mkdir -p CocoaLumberjack/{}
find . -name '*.h' |xargs -I {} cp {} CocoaLumberjack/{}find支持多个条件表达式的not-and-or组合, 语法与test相同
find . -name "file*.txt" -o -name "my*.txt"hostname显示或设置当前系统的名字
ulimit显示当前系统的文件句柄上限设置LANG环境变量,可以让date命令的月份,显示成英文
$ LANG=en_US.UTF-8
$ date
Wed Oct 28 20:20:31 CST 2015
$ LANG=zh_CN.UTF-8
$ date
2015年10月28日 星期三 20时20分51秒 CST删除n天前的文件
find /usr/local/backups -mtime +10 -name "*.*" -exec rm -rf {} \;
将/usr/local/backups目录下所有10天前带"."的文件删除touch a.txt
mv a{.txt,.xxx}
大括号拓展。(通配(globbing))将对大括号中的文件名做扩展。在大括号中,不允许有空白,除非这个空白被引用或转义。第一种:对大括号中的以逗号分割的文件列表进行拓展。如 touch {a,b}.txt 结果为a.txt b.txt。第二种:对大括号中以点点(..)分割的顺序文件列表起拓展作用,如:touch {a..d}.txt 结果为a.txt b.txt c.txt d.txt
bogon:/home/bash # ls {ex1,ex2}.sh
ex1.sh  ex2.sh
bogon:/home/bash # ls {ex{1..3},ex4}.sh
ex1.sh  ex2.sh  ex3.sh  ex4.sh
bogon:/home/bash # ls {ex[1-3],ex4}.sh
ex1.sh  ex2.sh  ex3.sh  ex4.sh
在XCode中,通过Pre-Actions,修改COMMIT_VERSION_HASH的值为Git提交号。Pre-Actions在Product->Scheme->Edit Scheme->Build->Pre-Actions->Run Script
cd `dirname $WORKSPACE_PATH`;
sed -i '' -e "/#define COMMIT_VERSION_HASH/s/\".*\"$/\"$(COMMIT_VERSION_HASH=$(git rev-parse HEAD | cut -c -8); COMMIT_USER_NAME=$(git config user.name); if [ $(git status -s|wc -l) -eq 0 ]; then echo ${COMMIT_VERSION_HASH}'_'${COMMIT_USER_NAME}; else echo ${COMMIT_VERSION_HASH}'+_'${COMMIT_USER_NAME}; fi;)\"/" Classes/UI/ServerButtonGroup.hprintenv可以打印当前shell的环境变量
dirname可以获取字符串中的路径
basename可以获取字符串中的文件名
sed的in-place(原位)替换
sed -i ‘’ -e ’s/src/dst/‘ myFile.txt
if [ 0 -eq 1 ]; then echo ‘eq’; else echo ’neq’; fi;#if-else的单行写法
for i in 1 2 3 5 7; do echo $i; done;#for的单行写法
在for循环中执行后台(background)命令:http://stackoverflow.com/questions/12472933/loop-background-job
for i in $(seq 3); do echo $i ; sleep 2 & done
BTW, such loops are better written on separate lines with proper indentation (if you are writing this in a shell script file).for i in $(seq 3)
doecho $isleep 2 &
done
#在for中使用数组
AARS=(widget player)
for aar in ${AARS[@]}; do echo $aar; done;# Bash下, 字符串转数组
# http://blog.csdn.net/bbjsbbpz/article/details/50285079
x='au bn cn hs sg vn'
x=($x) #<<<<<<<<<<<<<<<这里是关键
echo ${x[0]} #<<<<<<<<<<<<<<<注意这里
# au
echo ${x[1]}
# bn# Zsh下, 字符串转数组
x='au bn cn hs sg vn'
x=($(echo $x)) #<<<<<<<<<<<<<<<注意这里
echo ${x[1]} #<<<<<<<<<<<<<<<注意这里
# au
echo ${x[2]}
# bn数组长度 http://www.cnblogs.com/chengmo/archive/2010/09/30/1839632.html
len=${#array[*]}数组中某个元素的长度
a=('a' 'bc' 'def' 'gh')
echo ${#a[3]} # 3
echo ${#a[4]} # 2连接字符串
$value1=home
$value2=${value1}"="
echo $value2在Linux下,一个文件也有3种时间,分别是:访问时间、修改时间、状态改动时间。
1、Access时间,读一次这个文件的内容,这个时间就会更新。比如对这个文件运用 more、cat等命令。ls、stat命令都不会修改文件的访问时间。
2、Modify时间, 修改时间是文件内容最后一次被修改时间。比如:vi后保存文件。ls -l列出的时间就是这个时间。
3、Change时间   是该文件的i节点最后一次被修改的时间,通过chmod、chown命令修改一次文件属性,这个时间就会更新。
使用stat可以查看全部3个时间,使用ls,可以分别查看3个时间
ls -lu filename 列出文件的 atime
ls -l   filename 列出文件的 mtime
ls -lc filename 列出文件的 ctime使用dd,固定大小的生成随机文件
dd if=/dev/urandom bs=1024 count=1000000 of=/root/1Gb.file
dd if=/dev/zero bs=2048 count=500000 of=/root/1Gb.file
dd if=/dev/zero of=100mbfile bs=1024 count=100000修改swap分区的大小
把这个文件变成swap文件
mkswap /swapfile
启用这个swap文件
swapon /swapfile
在每次开机的时候自动加载swap文件, 需要在 /etc/fstab 文件中增加一行
/swapfile swap swap defaults 0 0判断当前用户是否是root
if [[ $EUID -ne 0 ]]; thenecho "Error:This script must be run as root!"exit 1
fiUbuntu Server下配置UTF-8中文环境,ubuntu server zh_CN.UTF-8
apt-get install language-pack-zh-hans
或(繁体)
apt-get install language-pack-zh-hant
vi /var/lib/locales/supported.d/local
内容是:
en_US.UTF-8 UTF-8
zh_CN.UTF-8 UTF-8
保存后 ,执行命令:
sudo locale-gen
修改缺省的编码为zh_CN
vi /etc/default/locale
LANG="zh_CN.UTF-8"
重启Ubuntu Server
reboot
可以用locale查看一下环境变量…
localesocket: Too many open files (24) apache bench lighttpd,报错的解决方法:
ulimit -n 10000# 显示全部进程的pid ppid pgid command cpu
ps -e -o pid= -o ppid= -o pgid= -o command= -o pcpu=|less# -o command 显示"command and arguments"
# -o comm 显示"command"
# -o comm= 显示带标题的"command"
# -o etime 显示进程从启动到现在的时间, 格式为"[[dd-]hh:]mm:ss"
# http://unix.stackexchange.com/questions/7870/how-to-check-how-long-a-process-has-been-running# -x参数对-o参数比较友好
ps -x -o command# 显示某个进程的command cpu
ps -o "%C %c" 4325# 检查进程是否存在: 如果存在, 则返回结果大于0
ps -ef | grep 程序名| grep -v grep  | wc -lps S用于显示后台进程# linux上的ps按照内存使用量降序排序
ps aux --sort -rss
# MacOS上是
ps aux -m
# 显示线程信息
# UID为User ID.
# PID为processid,进程标识符
# PPID为 parent processid,父进程标识符2,
# LWP为light weight process orthread, 轻量级进程,即线程标识符
# NLWP为,number oflwps(threads) in the process, 线程的数量
ps -efL# 查询某个进程组(pgid)下面的所有进程id
pgrep -g 18322top刷新2次后,自动退出
top -n 2计算字符串长度
echo 'Alex'|awk '{print length($0)}'
或者
name=Alex; echo ${#name}定义函数:
get_revs(){cnt=0for host in ${HOSTS[@]};doecho -n "$host: "host_head=$(curl "http://$host/deploy/server_info" 2>/dev/null |grep -o '[0-9a-f]\{40\}')echo $host_headif [ "$host_head" = "$HEAD" ];thencnt=$(($cnt + 1));fidone;return $cnt;
}
调用函数并获取返回值
get_revs
cnt=$?;
echo 'cnt = '$cnt;查ETIMEDOUT
man errno 删除20天前的日志文件;将日志文件归档为file-yyyymmdd.tar.gz;使用cronjob按照daily执行,将该脚本复制到/etc/cron.daily目录下
#!/bin/bash
dir=/letv/git/api_port/logs;
file=access.log;
date_file=$file-$(date +%Y%m%d);
find $dir -mtime +20 -name "$file-*.tar.gz" -exec rm -rf {} \;
cd $dir && /bin/cp -f $file $date_file && echo > $file && tar -czf $date_file.tar.gz $date_file && rm -f $date_file;使用fs读文件:
var fs = require('fs');
var rs = fs.readFileSync('ip_geo', 'utf8');// !!!注意: 设置encoding后, readFileSync返回的是String, 否则是Buffer
var rows = rs.split('\n');
console.log('rows.length = ' + rows.length);使用readline按行读取文件:
var readline = require('readline');
var rl = readline.createInterface({input: fs.createReadStream('ip_geo')});
rl.on('line', (line)=>{console.log(‘line = ' + line);});
rl.on('close', ()=>{console.log(‘read finished');});批量重定向tee的输出
方法1:http://unix.stackexchange.com/questions/61931/redirect-all-subsequent-commands-stderr-using-exec
#!/bin/bash
{somecommand somecommand2somecommand3
} 2>&1 | tee -a $DEBUGLOG
方法2:http://stackoverflow.com/questions/3173131/redirect-copy-of-stdout-to-log-file-from-within-bash-script-itself
#https://www.gnu.org/software/bash/manual/bash.html#Process-Substitution
#!/usr/bin/env bash
# Redirect stdout ( > ) into a named pipe ( >() ) running "tee"
exec &> >(tee -i logfile.txt)生成1~100,共计100个的连续数字,
seq 1 100可以使用ntpdate同步服务器时间:
/usr/sbin/ntpdate -B tiger.sina.com.cn
但是这种方法会导致服务器时间跳变,可以在服务器启动的时候调用,
服务器运行过程中应该使用ntpd后台进程同步查询yum安装的文件的路径
首先 rpm -qa php70-php-fpm|less
然后 rpm -ql php70-php-fpm-7.0.8-1.el6.remi.x86_64basename sendEmail-v1.56/mail.sh
# mail.sh
dirname sendEmail-v1.56/mail.sh
# sendEmail-v1.56
echo $(cd `dirname $0`; pwd)
# /letv/git/zabbix/sendEmail-v1.56$_放在脚本的第一行执行,用于打印脚本的执行绝对路径;放在其他位置,用于表示上一条命令的最后一个参数
$!用于表示上一条被放入后台执行的job的pid提取命令行选项
http://stackoverflow.com/questions/192249/how-do-i-parse-command-line-arguments-in-bash
for opt in "$@"
docase $opt in--country-code=*)country_code="${opt#*=}";;--npm-install=*)npm_install="${opt#*=}";;*)echo "Not supported options: $opt";;esac
done$(cat file)可以直接写成$(< file), 如echo "$(cat file)"可以写成echo "$(< file)"使用echo输出带颜色的文本:
http://stackoverflow.com/questions/5947742/how-to-change-the-output-color-of-echo-in-linux
echo -e "\033[44;37;5m ME \033[0m COOL"for i in {1..10}; do echo $i; done;
for i in {a,b,c}; do echo $i; done;ldd $(which ssh)/usr/share/zoneinfo 目录下存放了各种时区的信息date的格式
# 年-月-日T时:分:秒时区, 如2016-08-18T14:37:38+0800
date +%Y-%m-%dT%H:%M:%S%z
# 1970年1月1日0时至今的秒数
date +%s
# 月日T时分秒, 如0921T112940
date +%m%dT%H%M%S# 查看当前时区
date +"%Z %z"
# CST +0800# [[和[的区别
http://blog.csdn.net/yorkingalan/article/details/7055518
[[是bash里的关键字,可以使用!, &&, ||连接2个表达式, 可以使用<, >, ==运算符比较数字,而且&&和||会发生短路
[是内置(built-in)命令,不可以使用&&, ||连接2个表达式,不可以使用 <, >, ==运算符比较数字, !, -a, -o不会发生短路 # 安装inotifywait
yum install -y inotify-tools
# 使用inotifywait: 监听模式(-m), 递归监听目录里的文件(如果有的话, -r), 输出格式事件(%3), 监听的文件/目录(%w), 发生变化的文件(%f), 监听事件(-e)删除/移动文件本身
inotifywait -mr --timefmt '%Y/%m/%d-%H:%M:%S' --format '%e %w %f' -e delete_self,move_self ./data.txt# 输出全部(a), 数字化(n), TCP(t), UDP(u)的网络连接
netstat -antu# 修改系统的/etc/sysctl.conf配置来减少TIME_WAIT的tcp连接:
vi /etc/sysctl.conf
net.ipv4.tcp_syncookies = 1  (某些情况下该参数已启用)
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_fin_timeout = 30
# 然后/sbin/sysctl -p# 查询当前tcp_fin_timeout, tcp_tw_recycle, tcp_tw_reuse的值
cat /proc/sys/net/ipv4/tcp_fin_timeout
cat /proc/sys/net/ipv4/tcp_tw_recycle
cat /proc/sys/net/ipv4/tcp_tw_reuse# 调用top, 以Batch模式运行(-b), 只迭代1次(-n 1)
top -bn 1
# -b : Batch mode operation
#   Starts  top  in  Batch mode, which could be useful for sending output from top to other programs or to a file.  In this mode, top will not accept input and runs until the iterations limit youve set with the -n command-line option or until killed.# 跟踪sed修改文件过程中的系统调用, 注意, sed会删除/重建文件, 也就是说,原文件的inode值会发生变化
strace -e trace=file sed -i 's/5/10/' f# 静默强杀后台进程
# http://stackoverflow.com/questions/81520/how-to-suppress-terminated-message-after-killing-in-bash
kill -9 "$FROM_SRC_PID"
wait "$FROM_SRC_PID" 2>/dev/null# tr -d可以删除字符, 如删除空格( )和逗号(,)
echo 'hello, world'|tr -d ' ,'
# 去除重复的字符 :  -s 将连续的几个相同的字符压缩成为一个字符
echo aaacccddd | tr -s acd # acd
echo aaacccddd | tr -s abc # acddd
# 删除特定的字符或换行符等: –d 代表删除
cat myfile | tr -d '\n'
# 大小写相互替换,也可以利用字符类转换:
echo "Hello World"|tr '[A-Z]' '[a-z]' # hello world
echo 'Hello World'|tr H W # Wello World
echo 'Hello World'|tr '[:lower:]' '[:upper:]' # HELLO WORLD -> [:lower:] 代表小写字母 [:upper:] 代表大写字母# 查看kill支持的信号量
kill -l1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL       5) SIGTRAP6) SIGABRT      7) SIGBUS       8) SIGFPE       9) SIGKILL     10) SIGUSR1
11) SIGSEGV     12) SIGUSR2     13) SIGPIPE     14) SIGALRM     15) SIGTERM
16) SIGSTKFLT   17) SIGCHLD     18) SIGCONT     19) SIGSTOP     20) SIGTSTP
21) SIGTTIN     22) SIGTTOU     23) SIGURG      24) SIGXCPU     25) SIGXFSZ
26) SIGVTALRM   27) SIGPROF     28) SIGWINCH    29) SIGIO       30) SIGPWR
31) SIGSYS      34) SIGRTMIN    35) SIGRTMIN+1  36) SIGRTMIN+2  37) SIGRTMIN+3
38) SIGRTMIN+4  39) SIGRTMIN+5  40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8
43) SIGRTMIN+9  44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-7
58) SIGRTMAX-6  59) SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2
63) SIGRTMAX-1  64) SIGRTMAX# 判断参数是否为纯数字
if [ -n "$(echo $5|sed 's/[0-9]//g')" ]; then echo "<check_interval_sec>[$5] must be number"; exit 1; fi# top 10 最大的文件
du -a /var | sort -n -r | head -n 10# 查看一个命令是否是内置命令(built-in)
type -a fg bg jobs disown# 使用disown, 防止系统向1号任务发送SIGHUP信号
disown -h %1 # 仅阻止SIGHUP, 不从任务列表中移除任务
disown %1 # 从任务列表中移除任务, 不阻止SIGHUP# 查看系统中应用程序有权占用的端口范围(默认范围是:32,786-65,536)
# http://www.linuxscrew.com/2011/02/15/quick-tip-port-range/
cat /proc/sys/net/ipv4/ip_local_port_range
# 临时设置端口范围25000 ~ 65000
echo "25000 65000" > /proc/sys/net/ipv4/ip_local_port_range
# 永久设置端口范围25000 ~ 65000, 修改/etc/sysctl.conf
net.ipv4.ip_local_port_range="25000 65000"
# 然后重新加载配置文件
sysctl -p# Pipe Viewer可以查看管道(pipe)传输数据细节
# http://www.ivarch.com/programs/pv.shtml# iftop 可以显示网络io排序, 显示2/10/40秒的IO状况
# http://os.51cto.com/art/201404/435279.htm# iotop 可以显示磁盘io排序
# http://www.cnblogs.com/ggjucheng/archive/2013/01/13/2858941.html# read会单独开subshell给变量赋值, 使用应该使用while或者()或者{}处理变量
# http://stackoverflow.com/questions/374687/why-is-echo-foo-read-a-echo-a-not-working-as-expected
# 下面写法是错误的, 无货
echo foo | read a; echo $a; # 无货
# 下面3种写法是正确的, 有货
echo foo | while read a; do echo $a; done
echo foo | (read a ; echo $a)
echo foo | { read a; echo $a; }
# 也可使用<<<实现Here String,如:
# https://www.gnu.org/software/bash/manual/bash.html#Here-Strings
read a b c <<< $(echo 1 2 3)
echo $a $b $cfile=/dir1/dir2/dir3/my.file.txt
我们可以用 ${ } 分别替换获得不同的值:
${file#*/}:拿掉第一条 / 及其左边的字符串:dir1/dir2/dir3/my.file.txt
${file##*/}:拿掉最后一条 / 及其左边的字符串:my.file.txt
${file#*.}:拿掉第一个 . 及其左边的字符串:file.txt
${file##*.}:拿掉最后一个 . 及其左边的字符串:txt
${file%/*}:拿掉最后条 / 及其右边的字符串:/dir1/dir2/dir3
${file%%/*}:拿掉第一条 / 及其右边的字符串:(空值)
${file%.*}:拿掉最后一个 . 及其右边的字符串:/dir1/dir2/dir3/my.file
${file%%.*}:拿掉第一个 . 及其右边的字符串:/dir1/dir2/dir3/my
记忆的方法为:
# 是去掉左边(在鉴盘上 # 在 $ 之左边)
% 是去掉右边(在鉴盘上 % 在 $ 之右边)
单一符号是最小匹配﹔两个符号是最大匹配。${file:0:5}:提取最左边的 5 个字节:/dir1
${file:5:5}:提取第 5 个字节右边的连续 5 个字节:/dir2 我们也可以对变量值里的字符串作替换:
${file/dir/path}:将第一个 dir 提换为 path:/path1/dir2/dir3/my.file.txt
${file//dir/path}:将全部 dir 提换为 path:/path1/path2/path3/my.file.txt# 利用 ${ } 还可针对不同的变量状态赋值(没设定、空值、非空值):
${file-my.file.txt} :假如 $file 为空值,则使用 my.file.txt 作默认值。(保留没设定及非空值)
${file:-my.file.txt} :假如 $file 没有设定或为空值,则使用 my.file.txt 作默认值。 (保留非空值)
${file+my.file.txt} :不管 $file 为何值,均使用 my.file.txt 作默认值。 (不保留任何值)
${file:+my.file.txt} :除非 $file 为空值,否则使用 my.file.txt 作默认值。 (保留空值)
${file=my.file.txt} :若 $file 没设定,则使用 my.file.txt 作默认值,同时将 $file 定义为非空值。 (保留空值及非空值)
${file:=my.file.txt} :若 $file 没设定或为空值,则使用 my.file.txt 作默认值,同时将 $file 定义为非空值。 (保留非空值)
${file?my.file.txt} :若 $file 没设定,则将 my.file.txt 输出至 STDERR。 (保留空值及非空值))
${file:?my.file.txt} :若 $file 没设定或为空值,则将 my.file.txt 输出至 STDERR。 (保留非空值) # 还有,${#var} 可计算出变量值的长度:
${#file} 可得到 27 ,因为 /dir1/dir2/dir3/my.file.txt 刚好是 27 个字节...# http://stackoverflow.com/questions/374687/why-is-echo-foo-read-a-echo-a-not-working-as-expected
# http://www.cppblog.com/kenwell/archive/2010/06/25/118723.html
# Shell中的管道(Pipe)是通过subshell实现的: 管道两边的命令会分别被放到subshell中并行执行, 管道左侧的subshell的stdout会被重定向为管道右侧subshell的stdin
# 下面的管道只sleep 1秒
sleep 1|sleep 1|sleep 1
# 下面的read会结束, 是以为sleep 1执行完成后, 给read a发送了EOF
sleep 1|read a
# 下面不会输出任何内容, 因为read a中的a变量和echo $a中的a变量属于不同的subshell
echo 'xxx'|read a|echo $a管道(pipe |)的优先级更高, 先运行|, 再运行&&
# https://www.quora.com/Whats-the-precedence-of-bashs-pipe-and-operator
I happen to have 36 files in my directory.
$ ls && ls | wc -l
<list of files...>
36
This yields one ls result and one count of lines (36 files in my case).$ ls | wc -l && ls | wc -l
36
36But you can use curly brackets to group commands.
$ { ls && ls; } | wc -l
72
This yields the number 72, i.e. twice the number of files in my directory.管道的返回值是最后一个命令的返回值
ls xxx|ls / # 0
ls / | ls xxx # 1# 查看eth0网卡的网速, 全/半双工
# http://man.linuxde.net/ethtool
# https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Deployment_Guide/s1-ethtool.html
sudo ethtool eth0# 跟netstat类似的链接查看命令
ss -s# oh-my-zsh会在粘贴(paste)的时候自动转义特殊字符(safe-paste), 这很让人头疼(这不是mac OS或者terminal或者iTerm2的问题...)
# http://unix.stackexchange.com/questions/293472/paste-url-into-terminalurxvt-zsh-failed-some-characters-get-escaped
# 如:
http://example.com/?a=c
# 会变成:
http://example.com/\?a\=c# 设置coredump文件大小为0, 即关闭coredump
ulimit -c 0
# (临时)设置coredump的文件路径及格式
echo '/tmp/core_%e.%p' | sudo tee /proc/sys/kernel/core_pattern
# (永久)设置coredump的文件路径及格式
sysctl -w kernel.core_pattern='/tmp/core_%e.%p'
sysctl -p# 判断Linux是否运行在虚拟机上:
# linux 下dmidecode看System Information # 列出所有网卡
/etc/init.d/network status# 判断是否拔网线
ethtool eth1 # 检查"Link detected"是yes还是no# 假如文件中每行第一个元素是 FIND,如何获取第二个元素
awk'{ if ($1 == "FIND") print $2}'# 如何调试 bash 脚本
#!/bin/bash –xv# 两个整数相加
A=5
B=6
let V3=$V1+$V2 # 方法1
echo $(($A+$B)) # 方法 2
echo $[$A+$B] # 方法 3
expr $A + $B # 方法 4
echo $A+$B | bc # 方法 5
awk 'BEGIN{print '"$A"'+'"$B"'}' # 方法 6# 什么时候要在 [ condition ] 之前使用 “if” ?
# 当条件满足时需要运行多条命令的时候。# 用 awk 列出 UID 小于 100 的用户
awk -F: '$3<100' /etc/passwd# 打印最后5个字符
var=1234567890-+
echo ${var: -5}# 列出第二个字母是 a 或 b 的文件
ls -d ?[ab]*# 小写替换成大写
echo abc|tr '[:lower:]' '[:upper:]'# 生成步进为3的序列
for i in {0..100..3}; do echo $i; done# 判断字符串是否以ab开头, 注意使用双中括号([[ ]]), 并且ab*不能使用引号
[[ 'abc' == ab* ]]   # 正确
[[ 'abc' == 'ab*' ]] # 错误# 打印数组的全部索引
arr=(1 2 3 4 5)
echo ${!arr[@]} # 0 1 2 3 4
unset arr[1]
echo ${!arr[@]} # 0 2 3 4# 查找并杀掉(-k)正在使用挂载点(-m)/media/share的进程
# http://blog.csdn.net/radkitty/article/details/5337304
fuser -m -k /media/share# sudo执行内置命令(built-in command)
# http://askubuntu.com/questions/291666/why-doesnt-sudo-cd-var-named-work
# 1. 以root身份login, 然后执行, 最后退出
sudo -i
cd /var/named
exit
# 2. 开启一个新的shell, 然后执行,最后Ctrl + D退出
sudo -s
cd /var/named
Ctrl + D# 在/etc/sudoers文件里配置允许sudo的用户/组
# http://www.thegeekstuff.com/2010/09/sudo-command-examples/
sathiya    ALL=(ALL) ALL
# sathiya : name of user to be allowed to use sudo
# ALL : Allow sudo access from any terminal ( any machine ).
# (ALL) : Allow sudo command to be executed as any user.
# ALL : Allow all commands to be executed.
%programmers    ALL=(ALL) ALL
# programmers : name of group to be allowed to use sudo. Group name should be preceded with percentage symbol.
# ALL : Allow sudo access from any terminal ( any machine ).
# (ALL) : Allow sudo command to be executed as any user.
# ALL : Allow all commands to be executed.ls -l dir/somefile*
# -rw-r--r-- 1 root root 0 Dec  6 17:24 dir/somefile
# -rw-r--r-- 1 root root 0 Dec  6 17:32 dir/somefile_other
ls -l somefile.ext
# -rw-r--r-- 1 root root 0 Dec  6 17:24 somefile.ext
find dir -name somefile* -ls
# 你会发现上述find命令没有输出,即没有找到dir/somefile。这里有个坑,不是find的,而是shell的。
#
strace -e execve find dir -name somefile* -ls
# execve("/usr/bin/find", ["find", "dir", "-name", "somefile.ext", "-ls"], [/* 18 vars */]) = 0
# 用strace观察,"find dir -name somefile* -ls"由于shell对*号的自动扩展,实际变成:
find dir -name somefile.ext -ls
#
# 这条命令当然找不到dir/somefile。解决办法是避免shell对*号的自动扩展,比如:
find dir -name "somefile*" -ls
# 441426    0 -rw-r--r--   1 root     root            0 Dec  6 17:24 dir/somefile
# 441427    0 -rw-r--r--   1 root     root            0 Dec  6 17:32 dir/somefile_other# CentOS安装ldap
yum list '*ldap*'
yum install -y openldap-clients.x86_64history -c # 可以清除内存里[全部]的命令历史记录,
history -r ~/.bash_history # 使用指定文件里的内容载入到history的内存中
# 更灵活的Linux Shell历史命令调用方法:!!    前一条命令;!:0    不带参数的前一条命令名;!^    前一条命令的第一个参数;!:n    前一条命令的第n个参数;!$     前一条命令的最后一个参数;!*     前一条命令的所有参数,命令名除外;!n     第n条命令;!-n    倒数第n条命令;!str    最近一条以str开头的命令;!?str    最近一条包含str的命令;^a^b  将上一条命令名中的a替换为b;!:gs/a/b 将上一条命令的所有a替换为b(包含命令名和参数)。# 判断某个命令是否存在
# http://www.openskill.cn/article/518
command -v foo >/dev/null 2>&1 || { echo >&2 "I require foo but it's not installed.  Aborting."; exit 1; }
或
type foo >/dev/null 2>&1 || { echo >&2 "I require foo but it's not installed.  Aborting."; exit 1; }
或
hash foo 2>/dev/null || { echo >&2 "I require foo but it's not installed.  Aborting."; exit 1; }
或
[ -x "$(command -v foo)" ]

line-by-line方式合并2个文件

# http://stackoverflow.com/questions/3806874/how-to-concatenate-two-files-line-by-line-using-bash# paste方式
paste -d ' ' ts_ua uid > ts_ua_uid              # <<<< use ' ' as the field-separator(default \t) to concatenate 2 files# awk方式
awk 'BEGIN {OFS=" "}{getline line < "file2"print $0,line
} ' file1# Bash方式
exec 6<"file2"
while read -r line
doread -r f2line <&6echo "${line}${f2line}"
done <"file1"
exec 6<&-

exec, source, fork的区别(参考: Shell十三问)

  1. fork使用sub-shell的方式执行子脚本, sub-shell会继承一些父脚本的环境变量且有自己的PID, 在sub-shell中修改这些环境变量不会影响父脚本
  2. source在不会开启sub-shell, 这种方式只是在父脚本的上下文执行子脚本中的语句, 在子脚本中修改环境变量会影响父脚本
  3. exec与source类似, 唯一的不同是, 这种方式会终止父脚本的执行
  4. exec在不加参数的时候,仅用于重定向

获取当前TTY的名字/限制脚本仅能在TTY中执行

tty
# 输出如下
# /dev/pts/0

In this example, tar command will run, only if standard input is a terminal. Create a shell script called termtest.sh:

#!/bin/bash
# termtest.sh: Run the tar command only if command run from a termina
tty -s
status=$?if [ $status -eq 0 ]
thenecho "Running backup using tar command..."# tar cvf /dev/st0 /home
elselogger "$0 must run from a terminal"
fi

这样运行

chmod +x termtest.sh
./termtest.sh

只能root用户运行脚本


if [ `id -u` -eq 0 ];thenecho "root用户!"
elseecho "非root用户!"
fi

Shell整理(持续更新中)相关推荐

  1. Java自学视频整理(持续更新中...)

    1.Java基础视频 <张孝祥JAVA视频教程>完整版[RMVB](东西网) 历经5年锤炼(史上最适合初学者入门的Java基础视频)(传智播客) 张孝祥2010年贺岁视频:Java高新技术 ...

  2. 前端面试知识自己的一些整理 ---持续更新中

    - title: 自己整理的面试复习资料 date: 2019-03-20 12:27:51 tags: 面试 前端 CSS3+H5 [CSS3.0 帮助文档.chm](CSS3.0 帮助文档.chm ...

  3. 前端资料整理--持续更新中

    前端网站 1.http://www.wufangbo.com/   前端开发-武方博   包含有前端相关的各种文章.资源.开发工具等 2.http://www.w3cfuns.com/   前端网-云 ...

  4. Windows下bat批处理脚本常用场景整理,持续更新中。。。

    Windows下bat批处理脚本常用场景整理,持续更新中... 一.Winodws下使用bat脚本对结果进行筛选 例如:在筛选出来的结果中,筛选是否有"$G"字段 adb shel ...

  5. 2020今日头条面试真题及答案整理最新最全持续更新中~~~~

    大家好,我是好好学习天天编程的天天 一个整天在互联网上爬虫的程序员,每天给大家分享学习干货的攻城狮 2020今日头条面试真题及答案整理&最新最全&持续更新中~~~~ 2020今日头条面 ...

  6. 最值得收藏的 数字图像处理 全部知识点思维导图整理(武汉大学慕课课程)(持续更新中)

    本文的思维导图根据慕课上的武汉大学数字图像处理国家精品课程整理而来并标记出重点内容 思维导图就整理了这么多,之后应该也不会更新此内容了, 有需要的可以去 我的主页 了解更多学科的精品思维导图整理 本文 ...

  7. Android 高仿App项目归纳整理,持续更新中…

    Android 高仿App项目归纳整理,持续更新中- Android高仿App项目整理,包含高仿了一些大公司的app,有基于Java,Kotlin,Flutter等语言的.对于开发我们自已的项目时可以 ...

  8. 2020美团(开水团)面试题真题整理最新最全~持续更新中~~~

    大家好我是好好学习天天编程的天天 一个整天在互联网上种菜和砍柴的程序员~ 如果我们每天关注互联网行业,也有心做程序员的话,我们可能进场会听到一些关键词:一东(时间单位),一度(市值单位,一个拼多多是几 ...

  9. Android Studio 的一些 常用操作和 编译报错 整理(持续更新中...)

    Android Studio 的一些 常用操作和 编译报错 整理(持续更新中...) 目录 Android Studio 的一些 常用操作和 编译报错 整理(持续更新中...) 一.Android s ...

最新文章

  1. 计算机网络概述---传输层 UDP和TCP
  2. TortoiseSVN客户端重新设置用户名和密码
  3. 常见的几种最优化方法
  4. 前端学习(3283):立即执行函数二
  5. LeetCode 485. Max Consecutive Ones
  6. 接口自动化持续集成实战
  7. android 素材标签,Android Studio矢量素材资源导入错误 – 不支持标签
  8. 数据助力防疫,疫情密切接触人员追踪算法赛期待你的加入
  9. TcpClient Class
  10. Android将数据导出为excel文件的方法
  11. office Excel操作
  12. 盘点飞机上的各种警报
  13. 200多条影响谷歌SEO排名的因素大全
  14. #pragma clang diagnostic
  15. Tkinter 组件详解(七):Entry
  16. python怎么运行代码-python如何运行代码
  17. Soraの第一篇博客
  18. java外包项目有哪几类,java软件项目外包在选择合作平台时应注意哪些细节?
  19. 使用R语言抓取A股股价数据
  20. 获得任意风格的图片效果?深度学习算法一键P图!

热门文章

  1. 分布式消息队列之RocketMQ
  2. 关于Vue的nextTick的使用
  3. 如何修改mtk6573的设备号
  4. Shell - 查看目录文件(夹)大小并清理磁盘空间
  5. C++ 双冒号作用域运算符
  6. 我是程序员,我在深圳卖肉夹馍
  7. 论文笔记——YOLO-POSE
  8. vue整合uniapp_基于vue+uniapp直播项目|uni-app仿抖音/陌陌直播室
  9. 有赞微社区怎么做?社区运营全攻略,商城营销必备技能
  10. halcon 字符识别(点阵字符)