shell 脚本的第一行一般为:
#! /bin/sh
ll /bin/sh 可以发现 sh 是一个指向 bash 的软连接。脚本文件一般有两种运行方式,一种是作为 sh 命令的命令行参数,另一种是将脚本作为具有可执行权限的可执行文件,对于后一种方式来说,上面的那句话就有作用了,它指定了调用哪种解释器来运行脚本。
date:用于显示和设置时间
#输出时间: date #以本地时间格式输出当前时间 date +%s #以时间戳形式输出当前时间 #本地时间格式与时间戳转换: date +%s -d "2013/9/23 10:40:00" #将指定时间转换成时间戳>格式 date -d @1379895103 #指定时间戳转换成本地时间格式 #设置时间: date -s 2013/9/23 # date -s 2013-9-23 date -s 10:30:00 date -s "2013/9/23 10:30:00"
time:计算某一任务运行的时间。通过 type -a time 查看,可以发现 linux 中有两个 time,还有一个是 /usr/bin/time ,没有可安装,它显示的信息比下面会更多一些,包括一些CPU占用和IO等情况,使用方法如 /usr/bin/time -v make -j4,此处略过。
# TIMEFORMAT 环境变量用来自定义输出的时间格式 export TIMEFORMAT=$'real %2R user %2U sys %2S' # 有 -p 参数的时间格式 time date export TIMEFORMAT=$'real %2R ' # 只输出 real 时间 time date export TIMEFORMAT=$' real %3lR user %3lU sys %3lS' #默认时间格式 time date time -p date # -p 参数可以指定以 POSIX 缺省时间格式打印结果,单位为秒
who: show who is logged on
who -aH #输出系统上次引导时间、当前运行级别和当前登陆用户,及其它用户登陆信息,-H 表示显示表头(即标题) who -b # -b: boot 上次引导时间 who -r # -r: run 当前运行级别,同 runlevel who -u # -u: user 当前登录用户 whoami # 只输出当前登录用户的用户名
wc 计算机文件中的行数、单词数和字符数
wc -l /etc/passwd # -l: line 行数 wc -w /etc/passwd # -w: word 行数 wc -c /etc/passwd # -c: char 行数 wc -l ~/code/src/*.cpp # 依次输出 ~/code/src/*.cpp 的行数与总量 ls -l *.cpp | wc -l # 查看当前目录有多少个 *.cpp 文件
cp 复制命令
cp -u # -u: update 当源文件比目标文件新的时候,才复制 cp -p # -p: preserve 保持源文件的属性:模式,所有权,时间戳 cp -s # -s: symbolic-link 软连接,同 ln -s ,ln 默认为硬连接
注:硬连接(Hard Link):硬连接指通过索引节点来进行连接。在Linux的文件系统中,保存在磁盘分区中的文件不管是什么类型都给它分配一个编号,称为索引节点号(Inode Index)。在Linux中,多个文件名指向同一索引节点是存在的。一般这种连接就是硬连接。硬连接的作用是允许一个文件拥有多个有效路径名,这样用户就可以建立硬连接到重要文件,以防止“误删”的功能。其原因如上所述,因为对应该目录的索引节点有一个以上的连接。只删除一个连接并不影响索引节点本身和其它的连接,只有当最后一个连接被删除后,文件的数据块及目录的连接才会被释放。也就是说,文件真正删除的条件是与之相关的所有硬连接文件均被删除。
软连接(Symbolic Link):软链接文件有类似于Windows的快捷方式。它实际上是一个特殊的文件。在符号连接中,文件实际上是一个文本文件,其中包含的有另一文件的位置信息。
mkdir 创建目录
mkdir -pv -m=rwx test/test # -p: parents 两个作用:1、可以创建需要的多级目录。2、即使目录存在,也不报错 # -v: verbose 创建详情,如果创建成功则输出信息 # -m: mode 创建时赋予权限,同 chmod
不同文件的特殊字符标识:可以通过 ls 命令查看,也可以通过 file 命令。
- # 普通文件,如文本文件,二进制文件等 d # 目录 l # 符号连接文件(软连接) c # 字符特殊文件,提供对设备不带缓冲的访问,每次访问长度可变。 b # 块特殊文件,提供对设备带缓冲的访问,每次访问以固定长度为单位进行。 p # 命名管道,用于进程间通信(IPC) s # sockek,用于进程间网络通信
chmod 修改权限
chmod 777 src # 777 分别设置 usergroupother 三者(all)权限,八进制方式,1表示执行,2表示写,4表示读,相加得复合权限,八进制方式只能设置权限,而不能增加或去除权限 chmod a-x src # =/+/- rwx 用于赋予或增加或去除权限,a 表示 all,也可为 u,g,o ,也可写成 ugo-x,默认不写为 a chmod u+rwx,g+x,o=rw src # 同上,可以在一起分别设置 chmod a+x -R src # 递归修改目录权限 chmod a+x -v src # 输出修改成功后的权限信息
chown 和 chgrp : 修改所有者和所有组
chown -v -R root filename # 修改所有者 -R 表示递归修改,-v 输出修改结果 chown -v root:root filename # 修改所有者和所有组 chown -v :root filename # 只修改所有组,同 chgrp chgrp -v root filename # 同上
后台进程:
可以在执行命令时,在命令后面加上 & 符号,使其在后台运行。如 make & ,但作业在后台运行一样会将结果输出到屏幕上,干扰工作。可以通过如下方式,把输出重定向到文件:
make -j8 > result 2>&1 &
make -j8 1> /dev/null & #将标准输出扔掉,将错误输出仍默认输出到终端
另外,对于正在运行的作业,也可以通过 Ctrl+Z 键盘挂起作业,然后通过 bg %jobnumber 来令其在后台运行(相应的,可以使用 fg %jobnumber 令其在前台运行),并可以通过 jobs 命令查看当前挂起和在后台运行的作业。,%jobnumber是通过jobs命令查到的后台正在执行的命令的序号(不是pid)
当关闭 shell 窗口时,由于父进程是当前终端 shell 的进程,而一旦父进程退出,则会发送 hangup 信号给所有子进程,子进程收到 hangup 以后也会退出。如果我们要在退出 shell 的时候继续运行进程,则需要使用 nohup 忽略 hangup 信号,或者 setsid 将将父进程设为 init 进程。
但是最好的方式,还是使用 screen
关于后台进程,参见 http://blog.sina.com.cn/s/blog_3e3be35e0100oi9i.html
有两种方法执行shell scripts,一种是新产生一个shell,然后执行相应的shell scripts;一种是在当前shell下执行,不
再启用其他shell。
新产生一个shell然后再执行scripts的方法是在scripts文件开头加入以下语句
#!/bin/sh
一般的script文件(.sh)即是这种用法。这种方法先启用新的sub-shell(新的子进程),然后在其下执行命令。
另外一种方法就是上面说过的source命令,不再产生新的shell,而在当前shell下执行一切命令。
exec命令在执行时会把当前的shell process关闭,然后换到后面的命令继续执行。系统调用exec是以新的进程去代替原来的进程,但进程的PID保持不变。因此,可以这样认为,exec系统调用并没有创建新的
进程,只是替换了原来进程上下文的内容。原进程的代码段,数据段,堆栈段被新的进程所代替。
exec与system的区别
(1) exec是直接用新的进程去代替原来的程序运行,运行完毕之后不回到原先的程序中去。
(2) system是调用shell执行你的命令,system=fork+exec+waitpid,执行完毕之后,回到原先的程序中去。继续执行下面的部分。
总之,如果你用exec调用,首先应该fork一个新的进程,然后exec. 而system不需要你fork新进程,已经封装好了。
详见:http://blog.csdn.net/cyberrusher/article/details/7253385
source filename 与 sh filename 及./filename执行脚本的区别在那里呢?source命令也称为"点命令",也就是一个点符号。
1.当shell脚本具有可执行权限时,用sh filename与./filename执行脚本是没有区别得。./filename是因为当前目录没有在PATH中,所有"."是用来表示当前目录的。
2.sh filename 重新建立一个子shell,在子shell中执行脚本里面的语句,该子shell继承父shell的环境变量,但子shell新建的、改变的变量不会被带回父shell,除非使用export。
3.source filename:这个命令其实只是简单地读取脚本里面的语句依次在当前shell里面执行,没有建立新的子shell。那么脚本里面所有新建、改变变量的语句都会保存在当前shell里面。
echo 和 printf
echo 默认结尾带换行符(可以通过 -n 参数取消),而 printf 默认结尾不带换行符。
#!/bin/bash echo Hello,World! # 不能输出分号,因为分号是命令界定符 echo 'Hello,World!' # 不能输出变量值,如 $PATH,只会原形即"$PATH" echo "Hello,World" # 不能输出 等特殊符号,不过可以使用 set +H 之后改变这一情>况 set +H echo "Hello,World!" echo "$PATH" echo "newline " # 仍然是不完美的,会直接输出 字符,需要加 -e 参数才能识 别转义字符 echo -e "e[1;31mThis is red texte[0m" # 一般 echo 只用于最简单的输出,对于稍微复杂点的输出,请使用 printf printf "$PATH Hello,World! " printf "%s %s " $PATH Hello,World
管道符 program1|program2
表示将前者的标准输出重置为后者的标准输入。 < 和 > 和 >> 也可将输入与输出连接到文件,管道却可以把两个执行中的程序衔接到一起
模拟登录脚本:
read -p "login as:" login printf "$login@" ifconfig eth0 | sed -n "2,2p" | awk '{printf substr($2,6)}' printf "'s password:" stty -echo read password < /dev/tty printf ' ' stty echo
pgrep 和 pkill
#!/bin/bash pgrep -l -u root sshd # -l: list 显示进程名,-u 指定进程所属用户,可以简写成 pgrep -luroot sshd pkill -9 -u root yychat # 等同于 pgrep -uroot yychat | xargs kill -9
pmap : 查看进程的内存映像信息
[root@localhost ~]# while true; do pmap -d 27841 | tail -1; sleep 2; done mapped: 502368K writeable/private: 64024K shared: 0K mapped: 502368K writeable/private: 64024K shared: 0K mapped: 502368K writeable/private: 64024K shared: 0K # mapped 表示该进程映射的虚拟地址空间大小,也就是该进程预先分配的虚拟内存大小,即ps出的vsz # writeable/private 表示进程所占用的私有地址空间大小,也就是该进程实际使用的内存大小 # shared 表示进程和其他进程共享的内存大小
read: 从键盘上读取
read var # 从键盘读取字符串放入 var read -p "login as:" var # -p: 提示信息 read -s "password:" var # -s: 不回显 read -n 2 var # -n: 读取 n 个字符 read -t 3 var # -t: 特定时限(秒) read -d ":" var # -d: 使用定界符结束输入
IFS: 内部字段分隔符(Internal Field Separator)
data="a,b,c" oldIFS=$IFS IFS=, # IFS默认值是空白字符(换行符、制表符或空格) for item in $data do echo Item:$item done; IFS=$oldIFS
if 语句
read -p "Enter x:" x read -p "Enter y:" y if [ $x > $y ] # 注意 [ ] 与之间的表达式必须要有空格 then echo "$x>$y" elif [ $x -lt $y ] then echo "$x<$y" else echo "$x==$y" fi # -eq: == # equal 也可以写成 = ,但注意,= 两边必须有空格,如果没有空格,就是赋值 # -ne: != # not equal # -gt: > # greater than # -lt: < # less than # -ge: >= # -le: <= # 简单条件语句的写法: # [ condition ] && action # 如果 condition 为真,则执行后面语句 # [ condition ] || action # 如果 condition 为假,则执行后面语句 # 此外,逻辑与/逻辑或 也可以写成: # [ condition1 -a condition2 ] # 逻辑与,或 [ condition1 ] -a [ condition2 ] # [ condition1 -o condition2 ] # 逻辑或,或 [ condition1 ] -o [ condition2 ] # 文件系统相关测试: # [ -f $file_var ]: 如果给定变量包含正常文件路径或文件名,则返回真 # [ -x $file_var ]: 如果给定变量包含的文件可执行,则返回真 # [ -d $file_var ]: 如果给定变量包含的是目录,则返回值,注:如果这里是 -c/-b/-L,则分别对应字符设备文件、块设备文件、符号链接 # [ -e $file_var ]: 如果给定变量包含的文件存在,则返回值 # [ -r $file_var ]: 如果给定变量包含的文件可读,则返回真,注:如果这里是 -w 表示可写 fpath="/etc/passwd" if [ -e $fpath ];then echo "File exits"; else echo "Don't exits"; fi # -eq: == # equal 也可以写成 = ,但注意,= 两边必须有空格,如果没有空格,就是赋值 # -ne: != # not equal # -gt: > # greater than # -lt: < # less than # -ge: >= # -le: <= # 简单条件语句的写法: # [ condition ] && action # 如果 condition 为真,则执行后面语句 # [ condition ] || action # 如果 condition 为假,则执行后面语句 # 此外,逻辑与/逻辑或 也可以写成: # [ condition1 -a condition2 ] # 逻辑与,或 [ condition1 ] -a [ condition2 ] # [ condition1 -o condition2 ] # 逻辑或,或 [ condition1 ] -o [ condition2 ] # 文件系统相关测试: # [ -f $file_var ]: 如果给定变量包含正常文件路径或文件名,则返回真 # [ -x $file_var ]: 如果给定变量包含的文件可执行,则返回真 # [ -d $file_var ]: 如果给定变量包含的是目录,则返回值,注:如果这里是 -c/-b/-L,则分别对应字符设备文件、块设备文件、符号链接 # [ -e $file_var ]: 如果给定变量包含的文件存在,则返回值 # [ -r $file_var ]: 如果给定变量包含的文件可读,则返回真,注:如果这里是 -w 表示可写 fpath="/etc/passwd" if [ -e $fpath ];then echo "File exits"; else echo "Don't exits"; fi # 字符串比较时,最好使用 [[ 和 ]] ,有时采用单中括号可能会有问题 # [[ -n $str ]]: 如果 str 包含的是非空字符串,则返回真 # [[ -z $str ]]: 如果 str 包含的是空字符串,则返回真 # test 用来执行条件检测,有助于过多使用中括号。 if test 3 -gt 1; then echo "3>1"; fi
复合命令:不同命令间用分号隔离,这样会依次执行。
普通用户帐号使用$作为提示符,root帐号使用 # 作为提示符。
shell 登录过程:
1、执行 /etc/profile,同时该文件内会遍历执行 /etc/profile.d/ 下的 *.sh 配置文件。
2、执行 .bash_profile (或 ~/.bash_login 或 ~/.profile),同时该文件内会执行 ~/.bashrc,而该文件内又会调用 /etc/bashrc
3、在退出 shell 时,会执行 ~/.bash_logout
man 有 8 个不同的指南组成:(我感觉下面说得太乱,需要重新找下资料)
1、命令
2、UNIX 系统调用
3、库,用来存储由 C 程序员使用的与内核无关的函数
4、文件格式,如 /etc/passwd 等文件的格式
5、同样是文件格式
6、包括了玩UNIX所带游戏的指令
7、设备驱动程序
8、系统维护