Linux基础知识_Shell编程笔记
以下是一些 常用功能 , 基于 centos 6.5 x64, 也有部分centos7 64 会有提示。
# cp /etc/localtime /etc/localtime.org # rm /etc/localtime # ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime #启用中文支持 vim /etc/profile export LC_ALL="zh_CN.UTF-8" export LANG="zh_CN.UTF-8" export LC_CTYPE="zh_CN.UTF-8" # en_US.UTF-8 还原 source /etc/profile netstat -nltp # 查看进程及端口 kill -9 **** # 杀死指定PID的进程 # 类似于 httpd / nginx 停止接受新连接,等当前连接停止,重载配置文件,重开日志文件,重启服务 kill -USR1 pid # 开机启动界面 ######################################## vim /etc/inittab # 6.5版本以下 systemctl set-default graphical.target # 7版本 设置图形界面启动 systemctl set-default multi-user.target # 由图形界面模式更改为命令行模式 ################################## useradd test passwd test su test # su是用来切换用户,但是之前的用户依然是登录状态. # su不加参数是默认切到root, 缺点是用户需要知道root密码. su - # 加了横线表示切换到root及根目录下. #### sudo 则是为普通用户临时提供root权限. #### 当用户使用sudo命令时, 系统会寻找/etc/sudoers文件,判断该用户是否有执行sudo权限 vim /etc/sudoers # 为新用户添加sudo权限. 这样test用户才可以使用sudo 或者直接使用visudo命令 test ALL=(ALL) ALL ### 用户 主机=(谁的身份) 命令 hadoop master=NOPASSWD: /bin/ls, /bin/cat # 只允许hadoop用户在master上免密执行ls, cat命令. ### 实际环境中,管理员会给普通用户配置sudo权限. sudo在执行带有重定向符号时,需要 sh -c "" 引号括起完整命令: sudo sh -c "echo 11111 > /data/test.txt" userdel -r test vim /etc/passwd #可以查看系统中的所有用户 root:x:0:0:root:/root:/bin/bash # 用户名:密码x:用户id0:组id0:描述信息root:用户根目录/root/:用户登录后的shell # x 是表示此处为空;采用shadow passwd,影子密码在 /etc/shadow 文件 # 命令别名定义 alias drm="rm -rf" # drm 代表了命令rm -rf unalias drm # 删除别名 alias # 查看别名 ls -lh --time-style=+"%Y-%m-%d %H:%M:%S" # 设置显示文件时间戳 ############################ network ############################### vim /etc/sysconfig/network-scripts/ifcfg-eth0 # centos7以后 ens33 DEVICE="eth0" BOOTPROTO="static" HWADDR="00:0C:29:F5:05:8E" NM_CONTROLLED="yes" ONBOOT="yes" TYPE="Ethernet" IPADDR=192.168.112.10 NETMASK=255.255.255.0 GATEWAY=192.168.112.2 DNS1=192.168.112.2 ##可删除HWADDR,UUID service network restart # 重启网络服务 ##网卡更换后,可编辑 vim /etc/udev/rules.d/70-persistent-net.rules # 将最后一条末尾改为 eth0 ,其它的网卡信息删除后保存 reboot # 重启 ifconfig # 网络信息 # CentOS7之后,如果网卡不能启动,出现“ journalctl -xe ”的提示时, 执行之后有“Failed to start LSB: Bring up/down networking” 时,可尝试以下命令: systemctl stop NetworkManager systemctl disable NetworkManager # 关闭自带网络管理套件 systemctl start network.service ifconfig # 如果正常则幸运解决 ## 可参考:http://blog.sina.com.cn/s/blog_6253d0970102xg3o.html curl www.taobao.com # 得到某 url 内容,顺便也可以看看是否显得出中文 curl -I www.baidu.com # 返回站点响应头 Server: Tengine # 如果有代理,也可以看到 X-Cache: 信息 netstat #网络端口监听 -a显示所有选项, -t仅显示TCP, -u仅显示UDP, -l仅列出有监听的. netstat -nltp # 查看有监听端口的进程 netstat -an |grep 'ESTABLISHED' |grep -i '8080' |wc -l # 8080的连接数 netstat -an |grep 'ESTABLISHED' |grep -i '27017' |wc -l # mongodb的连接数 netstat -an |grep 'ESTABLISHED' |wc -l # 总连接数 #修改hosts和主机名 # 修改/etc/hosts 以及/etc/sysconfig/network 文件, 分别设置不同的HOSTNAME vim /etc/hosts 192.168.112.10 master 192.168.112.11 slave1 192.168.112.12 slave2 hostname master vim /etc/sysconfig/network HOSTNAME=master ### CentOS7 以上,需要执行命令: hostnamectl set-hostname *** ### 关闭防火墙和 SELinux service iptables stop chkconfig iptables off # centos7 systemctl stop firewalld systemctl disable firewalld # selinux vi /etc/selinux/config # 将 SELINUX=disabled
常用命令与工具:
######################################### 资源 情况 #################### du -hs db # 显示db文件夹总大小 du -hs # 显示当前目录大小 也可以加 --max-depth=1 df -h # disk info df -hT # disk info with FileSystem df -h db # 查看db文件夹所在分区的磁盘使用情况 free # Memory top # 任务管理器 #------------------------ top ------------------------------------- top -p [PID] # 监控指定PID top -p 765,767,768 # 监控指定的三个 top -u user # 只显示user进程 top -c # 显示详细进程信息 P # CPU百分比排序 M # 内存 T # 累积CPU时间 s # 刷新间隔 k # 结束指定进程 cat /dev/null > create_data_prod_py.log # 清空这个日志文件 > 是覆盖输出, >> 是追加输出 echo > a.log # 清空日志 ## 重定向 ## 0 (STDIN) 1 (STDOUT) 2 (STDERR) date > a.txt # 是重写内容 date >> a.txt # 是附加内容 wall < /etc/issue.net # 输入重定向,广播了某文件的内容 ls /temp 2> ls.err # 错误重定向,出错时写入文件 数字2代表错误输出 cp -R /usr /backup/usr.bak 2> /bak.error # 备份出错时,保存记录 write user # 向用户user 发送消息 wall # 向所有用户发送消息 ### 管道 ll /etc | more # 将前一个命令的结果作为后一个命令的输入 ll /etc | grep init # 查看/etc下的以init筛选后的结果 ll /etc | grep init | wc -l # 管道连用,查看上面的结果有多少行. ## 命令连接符 ; && || pwd ; ls ; date # 就是类似于编程语言中分号的作用,命令依次执行。 ls && pwd # 逻辑与,第一个命令成功,才会执行第二个命令。失败则不执行第二个。 ls || pwd # 逻辑或,第一个命令成功,不执行第二个。失败则执行第二个。 ## 命令替换符 将后边命令的输出作为前边命令的参数 ll `which java` # 找到java后,列出目录 ## 如果要编译程序,通常需要安装依赖,可以一条命令多个组件. yum install gcc gcc-c++ automake autoconf libtool openssl-devel pcre-devel -y ## 以下是python2.7运行MySQLdb模块时,可能用到的: yum install gcc gcc-c++ -y yum -y install mysql-devel yum install python-devel pip install --upgrade pip pip install MySQL-python -i http://pypi.douban.com/simple --trusted-host pypi.douban.com
开机界面:
# 系统启动界面 systemctl get-default systemctl set-default multi-user.target # 设为命令行 systemctl set-default graphical.target # 设为图形界面
压缩解压:
# tar gz xz tar zcf a.tar.gz logs # common compress tar Jcf a.tar.xz logs # high compress tar zxf xxx.tar.gz # extract tar Jxf xxx.tar.xz # extract
gzip -9 xxx.log gzip -d xxx.log.gz # zip yum install -y zip unzip zip -r a.zip logs/ # 压缩 logs 目录到 a.zip unzip b.zip # 解压缩 unzip -l b.zip # rar cd /opt/ wget https://www.rarlab.com/rar/rarlinux-x64-5.9.0.tar.gz tar zxf rarlinux-x64-5.9.0.tar.gz ln -s /opt/rar/rar /usr/bin/rar ln -s /opt/rar/unrar /usr/bin/unrar # 7z yum install p7zip p7zip-plugins 7z a a.7z logs # compress 7z x a.7z # extract
yum 离线安装法
#--------------------------- 离线下载方式 ------------------------------ # 联网机 yum install yum-plugin-downloadonly # 安装下载工具 mkdir -p /data/rpm # 下载目录 yum install --downloadonly --downloaddir=/data/rpm samba # 下载某软件包及依赖 ll /data/rpm # 查看文件 ## 手动复制文件到内网机,或scp 或rsync # 内网机 mkdir -p /data/samba cd /data/samba rsync -a 192.168.52.6:/data/rpm ./ # 从远端复制文件过来 yum localinstall *.rpm -y # 安装当前目录下所有包
定时任务:
################################# crontab #################################
# crontab:
crontab -l #查看当前用户的crontab内容.
crontab -r #删除定时任务配置,如果不指定用户,则删除当前用户的.
crontab -e #编辑某个用户的crontab内容. 创建时也就先执行这个命令。
#crontab格式
#分 时 日 月 周 命令
0 0 * * * /shell/upFile2HDFS.sh #每天0点执行一次
*/1 * * * * date >> /test/date.txt #每分钟将时间写入文件
30 21 * * * /usr/local/etc/rc.d/httpd restart #每天21:30执行一次命令
20 0,4,8,12,16,20 * * * /data/test.sh # 0:20, 4:20, ... 20:20 执行脚本
0,30 18-23 * * 6,0 /usr/local/etc/rc.d/httpd restart #每个周六,周日的18点到23点,每隔30分钟
0 0 1-31/2 * * command # 单号执行
0 0 2-30/2 * * command # 双号执行
0 0 * * * * test $(((`date +%j` % 2))) != 0 && command # 单号执行
0 0 * * * * test $(((`date +%j` % 2))) == 0 && command # 双号执行
# 不要忘记开启crond服务。
yum -y install crontabs # 安装
service crond start # 启动服务
nohup python -u myscript.py >> a.log & # 指定脚本在后台运行。 nohup ... &
jobs -l # 可查看nohup跑的进程
ps -ef # 通过进程查看
netstat -ntp # 通过端口查看
## --------------------- 任务切换到后台运行 ----------------------------
# 以 scp -r 复制文件为例,因为要输密码,所以不能直接 nohup ... &
scp -r A005003/ 10.170.6.117:/data/mongobak # 复制文件到远端
# 输密码,开始传送:
ctrl + z # 暂停 出现jobs列表
bg %1 # 根据jobs的列表的任务号
jobs # 是否Running
disown -h %1 # 忽略hup信号
ps -ef |grep scp
logout
################################# 建立每台电脑的互信关系 #################################
ssh-keygen # 创建.ssh目录 ,一路回车即可. ssh-copy-id slave1 # 复制公钥到目标主机或IP ssh root@slave1 # 测试登录 ssh root@slave2 都能成功,不用密码,则互信成功.
修改yum源:
#----------------------------------------------------------------------# # 修改yum源为aliyun # 先备份: mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup # 下载配置文件 注意 centos版本 wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-6.repo yum makecache # 生成缓存
# 163 网址
wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.163.com/.help/CentOS7-Base-163.repo #----------------------------------------------------------------------# lsb_release -a # 查看发行版本号 如果需要安装 yum -y install redhat-lsb uname -a # 查看内核版本 cat /etc/os-release # 查看OS发行版
cat /etc/redhat-release # 具体版本 cat /etc/issue # 查看发行版 ulimit -a # 显示目前资源限制的设定 ulimit -n # 打开文件描述符的最大值 more /etc/*release # 更多信息 getconf LONG_BIT # 系统位数 uptime # 运行时间 load avg 为1m,5m,15m的CPU均值 last # 登录日志 w # 负载与用户连接情况 cat /proc/cpuinfo # 查看cpu核数 vmstat # 查看进程、cpu、memory、交换、io、系统 last reboot # 第一行是上次重启时间 who -b # 上次重启时间 # 参考: https://www.cnblogs.com/zhangmingcheng/p/6438994.html
设置时区时间相关
date -s "2018-01-01 14:22:33" # 修改时间 参数后面加字符串 clock -w # 写入硬件时钟 date -R #显示时区 tzselect #时区向导# 其实不考虑各个发行版的差异化, 从更底层出发的话, 修改时间时区比想象中要简单:
cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime #修改时区
# centos 7
sudo timedatectl --help # 系统时间控制台
sudo timedatectl # 显示时间信息
sudo timedatectl set-time 15:22:22 # 设置时间
sudo timedatectl set-time "2020-05-02 09:32:50" # 包括日期时间
yum install ntp # 安装ntp服务 ntpdate pool.ntp.org # ntp对时 chkconfig ntpd on /etc/init.d/ntpd start # centos7 改到了/sbin/ntpd clock -w # 写入硬件时钟 vim /etc/rc.d/rc.local # 可设置开机启动项目 并且要给此文件加可执行权限 已逐渐弃用,官方建议使用systemd #例如,在最后加上 /etc/init.d/mysqld start则可以启动mysqld
# centos7 若没有ifconfig,安装网络工具 ip addr yum -y install net-tools
# centos7 可以使用以下命令,安装大多数开发工具及依赖
yum groups info "Development Tools" # 查看
yum groups install "Development Tools" # 安装
# 此外,还有部分yum命令:
yum list installed # 查看已安装的包
yum list installed |grep docker # 查找是否安装docker
yum remove -y *gnome* # 删除所有包含gnome的包及其依赖
yum remove gnome-shell-3.26.2-5.el7.x86_64 # 单独删除某个包
yum install epel-release # 使用 epel 库,这个库带有很多第三方软件 如 nginx wget https://mirrors.aliyun.com/epel/7/x86_64/Packages/e/epel-release-7-12.noarch.rpm
# 也可以手动下载国内的epel源,然后安装 rpm -Uvh epel-release-7-12.noarch.rpm
yum update # 全部更新
yum update epel-release # 只更新指定包
yum install nginx # 安装 nginx
# 日期时间运算: echo $(date +"%F %T.%N" | cut -b 1-23) # 显示成常用log格式, 2020-07-23 07:58:03.116 echo $(date -d -10day +"%Y%m%d") # 显示10天前日期 20200713 单位可以是 year, month, day, week echo $(date -d -10min +"%F %T.%N" | cut -b 1-23) # 显示10分钟之前, 单位可以是 hour,min,sec, 可以加减 # %F 相当于 %Y-%m-%d , 而 %T 相当于 %H:%M:%S (24小时格式) %N是纳秒
rpm 命令:
rpm -qa |grep erlang # 查找已安装的 erlang 相关软件 rpm -Uvh rabbitmq-server # U 如果有旧版则升级安装 rpm -e --nodeps erlang-stdlib-R16B-03.18.el7.x86_64 # 卸载 忽略依赖,软件包
history命令:
-c:清除命令历史; -d:offset:删除指定命令历史; -r:从文件读取目录历史至历史列表中; -w:把历史列表中的命令追加至历史文件中 ~/.bash_history history 20 显示最近的20条命令; !542 执行第542条命令 # 添加环境变量: export HISTCONTROL=ignoreboth # 忽略空格开头忽略重复命令 export HISTTIMEFORMAT="%F %T " # 命令带日期时间
# 查找命令 find / -name tomcat # 找tomcat # 按常人理解的日期格式 ls -lh --time-style=+"%Y-%m-%d %H:%M:%S" # 显示所有全局变量 export
# shell多行注释
:<<!
被注释掉的内容
!d
\cp -rf . /opt/apps/screen-frontend/dist/ # \cp表示调用原生cp命令,-rf 表示递归处理及强制覆盖不提示 . 当前目录
Vim的操作:
############# vim ########################################### 命令模式下: 1)把光标移动到要复制的行上,按yy (复制当前行) 2)把光标移动到要复制的位置 ,按p (粘贴到指定行) 3)把光标移动到要复制的位置 ,按dd(删除当前行) 移动光标: hjkl 左下上右 ctrl+u:到文件头 ctrl+d:到文件尾 shift+h:到屏幕第一行,shift+m:到屏幕中间,shift+l:到最后一行, shift+zz 保存退出 :n 到第n 行 ^ 到行首,$ 到行尾 (这两个与正则一样) 查找并高亮: /name 查找 name n下一个,N上一个 替换 :%s/原/新 # 这是全部替换
取消高亮: :noh :r! pwd # 执行这个shell并将结果插入到当前行的下一行。 撤销更改:u:取消更改 插入:a从光标后,i从光标前,o从光标下一行
:set ff # 查看当前文本的模式类型,dos,unix
:set ff=dos # 设置为dos模式, 也可用 sed -i 's/$/\r/'?
:set ff=unix # 设置为unix模式,也可用 sed -i 's/.$//g'
:set fileencoding # 查看现在文本的编码
:set fenc=utf8 # 转换当前编码为utf8 cp936, gb18030 ...
列操作,比如每行开头加注释
ESC, Ctrl + v 进入visual
数字5,再下箭头,即可向下选中5行。
shift + i 插入,# 再按2次ESC,即可在所有选中行前插入#
按 d 即删除选中的部分
# Vim批量注释 ctrl+v 列编辑模式,上下移动光标,开头标记起来,按大写I(shift+i),插入注释符,比如"//",再Esc,就会全部注释 # 批量去掉注释 ctrl+v 列编辑模式,先上下,横向选中列的个数(如"//"注释符号,需要选中两列),然后按d, 就会删除注释符号 ##配置文件 vim /etc/vimrc set nu # 行号 set ts=4 # tab距离4空格 set et # tab转换为真正的空格 # modeline 相当于文件格式配置 # vim:et:ts=4:sw=4: ############# vim end #########################################
挂载硬盘与分区
# 先在虚拟机中添加硬盘,比如3T大小,不用关机,Centos7 可直接检测到 fdisk -l # 可以看到 Disk /dev/vdc: 3221.2GB vdc 表示这是第3块盘了。 # 挂载使用以下两种方式均可: #------------------------方式一: 整盘格式化,直接挂载 ------------------------- mkfs.xfs /dev/vdc # 直接格式化整盘,没有分区。注:fdisk 默认分区最大2T # ext4 文件系统逐渐老去,未来 xfs 将会取代。 mkdir /E mount /dev/vdc /E # 挂载到 /E df -h # Filesystem Size Used Avail Use% Mounted on # /dev/vdc 2.9T 89M 2.8T 1% /E # 写入文件试试。 # 需要系统启动时自动挂载,则 vi /etc/fstab 添加一行: /dev/vdc /E xfs defaults 1 2 # 磁盘 挂载点 文件系统 选项 0忽略/1允许dump fsck检查顺序0不检 # umount /E 不用时可以卸载 #------------------------ 方式二: 先分区再挂载 --------------------------------- # 开始分区 fdisk /dev/vdc m # 帮助 g # 开始创建GPT分区表(因为vdc大于2T,所以必须GPT) n # 开始创建分区,1号,然后一路默认回车。
t # 改变分区类型
L # 找到 Linux LVM 序号
31 # 这个序号对应 Linux LVM ,每台机器可能不同,以实际为准。 w # 保存 fdisk -l # 再次查看,得到以下信息: Disk /dev/vdc: 3221.2 GB, 3221225472000 bytes, 6291456000 sectors Disk label type: gpt Disk identifier: 2A96EF32-3BDB-4EAB-B7DB-113278422354 # Start End Size Type Name 1 2048 6291455966 3T Linux filesyste mkfs.xfs -f /dev/vdc1 # 格式化为XFS,等待数秒完成 mkdir /E mount /dev/vdc1 /E df -h # Filesystem Size Used Avail Use% Mounted on # /dev/vdc1 3.0T 33M 3.0T 1% /E # /dev/vdb 7.8T 1.8T 5.7T 24% /data # 需要系统启动时自动挂载,则 vi /etc/fstab 添加一行: /dev/vdc1 /E xfs defaults 1 2 # 磁盘 挂载点 文件系统 选项 0忽略/1允许dump fsck检查顺序0不检 # umount /E 不用时可以卸载
调整挂载点 /home的容量到根 /
df -h # 发现/dev/mapper/centos-root 所剩空间很少,而 /dev/mapper/centos-home 有size 42G sudo tar zcf /run/home.tar.gz /home # 打包home到run下,因为run有足够的空间可以暂存 yum install -y psmisc # 安装fuser sudo fuser -km /home # 结束 home相关进程 yum install -y lsof # 也可使用 lsof |grep /home/ 来查看占用home的进程,然后kill sudo umount /home # 卸载 sudo lvremove /dev/mapper/centos-home # 移除lv分区 sudo lvextend -L +30G /dev/mapper/centos-root # 增加root 30G sudo xfs_growfs /dev/mapper/centos-root # 扩大文件系统 sudo lvcreate -L 11G -n/dev/mapper/centos-home # 只剩11G,都给home, 如果超过可用大小,会有提示。 sudo mkfs.xfs /dev/mapper/centos-home # 格式化 sudo mount /dev/mapper/centos-home # 挂载 sudo tar zxf /run/home.tar.gz -C / # 恢复home
如果是VM之类的扩展了物理硬盘,则centos需要在系统中操作:
df -h # 查看当前容量 fdisk -l # 查看哪个分区容量明显多于上面显示的容量 fdisk /dev/sda # 下面是依次输入 m n # 新建 p # 数值默认 t # 改变system为 LVM 8e p # 显示分区表 ( 假设新分区为 sda3 ) w # 保存 reboot # 可能不需要重启 lvm # 进入LVM pvcreate /dev/sda3 pvdisplay # 显示卷信息 (假设要给sda2扩展容量,sda2的 VG name 是 centos vgextend centos /dev/sda3 # 加入和 sda2同一个VG组
pvdisplay # 记住 Free PE 数,如127999 exit lvextend -L +12G /dev/mapper/centos-root # 也可以按M单位增加也可执行多次,只要pvdisplay中还有 Free PE 或者使用下面一条:
lvextend -l +127999 /dev/mapper/centos-root # 这样更直接,避免浪费。 xfs_growfs /dev/mapper/centos-root # 执行容量增长
挂载windows的共享:
mount -t cifs -ro username=admin,password=123456 //192.168.1.12/share /opt/share
- username,password 是windows登录用户名密码
- //192.168.1.12/share 是windows的共享文件夹
- /share是希望Centos7将要挂载到的地方,可任意位置
开机启动就挂载文件夹,在/etc/fstab文件中添加
//192.168.1.12/share /share cifs username=admin,password=123456 0 0
知识点参考:http://www.jinbuguo.com/man/mount.cifs.html
如果失败,可能缺少组件。 yum install cifs-utils
挂载NFS
# ------------------------------- server ------------------------------- yum install -y nfs-utils vim /etc/exports # 共享目录,允许的网段,读写方式 /data 192.168.1.0/24(rw,async) # 准备共享目录并授权 mkdir /data/ chown -R nfsnobody.nfsnobody /data/ # 开启服务 systemctl start nfs systemctl enable nfs # 查看服务器端信息 rpcinfo -p 192.168.1.123 # 查看是否共享成功 showmount -e localhost # ------------------------------- client ------------------------------- yum install -y nfs-utils showmount -e 192.168.1.123 # 准备目录并挂载 mkdir /bak mount -t nfs 192.168.1.123:/data /bak # 开机自动挂载 vi /etc/fstab 192.168.1.123:/data /bak nfs defaults 0 0
shell编程一定要注意,变量名和=之间不能有空格; 原生bash不支持简单数学运算,必须借助expr表达式工具等。
对于习惯其它开发语言的人来说,这个shell的格式很容易让人出错。
想要掌握并记忆,还是要多写几次练习。
#!/bin/bash # 上面第一行是解释器 bash shell是Linux默认的免费的 ## 通常会在第二行开始写脚本说明,作者,时间等。 #chmod +x hello.sh # 给全部用户加上执行权限 脚本的执行需要有x权限 #chmod u+x hello.sh #给当前用户加上执行权限 chmod 755 hello.sh # 所有者 所属组 其他人。 7 = 4+2+1 表示拥有"读/写/执行"的权限 cat /etc/shells #查看当前系统中的所有shell ## 执行脚本时 -x 参数可以看到具体拭执行过程 ###################### shell 第一个例子:查看系统概况 ###################
# echo -e 参数可以识别字符串中的转义字符
#!/bin/sh # auto mail for sys info /bin/date +%F >> /tmp/sysinfo # 日期信息写入临时文件 echo "disk info:" >> /tmp/sysinfo /bin/df -h >> /tmp/sysinfo # 真正的disk信息 echo >> /tmp/sysinfo # 显示空行 echo "online users:" >> /tmp/sysinfo /usr/bin/who | /bin/grep -v root >> /tmp/sysinfo # 列出所有用户,不看root echo >> /tmp/sysinfo echo "memory info:" >> /tmp/sysinfo /usr/bin/free -m >> /tmp/sysinfo echo >> /tmp/sysinfo # write root /usr/bin/write root < /tmp/sysinfo && /bin/rm /tmp/sysinfo #信息发给root,然后删除 # crontab -e # 0 9 * * 1-5 script ###################### end 第一个例子 ################################## ###################### 变量 #################################### name="abcde" # 变量名和=之间不能有空格 export a='aaaaa' #声明为全局变量 # 在a.sh中调用b.sh 写上source则表示在同一个进程中执行. source ./b.sh . ./b.sh # 也可用. 来代替source echo "${name}s a bcd." # 大括号确定了变量的边界 注意需要使用双引号;单引号则不会识别变量 readonly aa=1234 # 只读变量aa,不可修改 unset a ## 删除变量 ##局部变量仅能在当前会话中访问. set ##set命令可以查看环境变量 ###################### 变量参数 #################################### #脚本内获取参数的格式为$n n代表数字, 1第一个参数,2是第二个参数,以此类推... #特殊符号: $#参数个数, $*所有参数为一个字符串, $$脚本运行的当前进程ID, $!后台运行的最后一个进程ID, $@ 与$*相同,但是使用时加引号,在引号中返回每个参数. $? 显示最后命令状态, $*与$@区别: 是否被双引号包含. #!/bin/bash echo "脚本名称: $0"; echo "第一个参数: $1"; echo "参数个数: $#"; echo "传递的参数作为一个字符串: $*"; echo "进程号: $$"; echo "结束: $?"; ###################### 第二个例子: 备份 ################################## # $1 利用了位置参数. 例如执行 sh autobak.sh /usr 时,$1 即表示/usr #!/bin/bash # backup files by date DATE=`/bin/date +%Y%m%d` /bin/tar -cf /backup/$1.$DATE.tar $1 > /dev/null 2>> /backup/$1.bak.log /bin/gzip /backup/$1.$DATE.tar if [ $? -eq 0 ] then echo "$1 $DATE backup successful" >> /backup/$1.bak.log else echo "ERROR: failure $1 $DATE backup!" >> /backup/$1.bak.log fi # crontab -e # 0 3 * * 2,5 script ###################### 第二个例子: 备份 ################################## ################################ shell 运算符############################## # 原生bash不支持简单数学运算,可借助expr表达式工具以及``符号 ,完成求值. # 其实``叫命令替换符 val=`expr 2+3` #输出2+3 val=`expr 2 + 3` #输出5 val=`expr 2 \* 3` #输出6 乘法要转义 val=`expr 2 / 3` #除法 val=`expr 2 % 3` #取模 #也可以用$(())或$[] 进行算术运算 #!/bin/bash count=1 ((count++)) echo $count a=$((1+2)) b=$[3+4] echo $a $b # 关系运算符 简称: -eq等于, -nq不等于, -gt大于, -lt小于, -ge大于等于, -le小于等于 # 关系运算符只支持数据,不支持字符串,除非是数字形字符串 #!/bin/bash a=10 b=20 if [ $a -eq $b ] then echo "$a -eq $b : a等于b" else echo "$a -nq $b : a不等于b" fi if [ 1 -lt 5 ]; then echo OK; else echo notok; fi ##单行写法. # 布尔运算符 -a且 -o或 只需单层方括号 if [ $a -lt 100 -a $b -gt 15 ] then echo "$a 小于100且 $b 大于15 : 返回true" else echo "$a 不小于100或 $b 不大于15 : 返回false" fi # 逻辑运算符 && 及|| 需要双层方括号 if [[ $a -lt 100 || $b -gt 100 ]] then echo "返回true" else echo "返回false" fi # 字符串运算符 #!/bin/bash a="" b="abc" if [ -z $a ] # 字符串长度为0返回true then echo "长度0" else echo "长度非0" fi if [ -n $b ] # 字符串长度不为0返回true 和-z相反 then echo "长度不为0" else echo "长度为0" fi ## if [ $a ] #字符串是否存在 # 文件测试运算符 #!/bin/bash file="/test/1.sh" if [ -r $file ] # -r 可读, -w 可写, -x 可执行, -d 是否目录 -f是否文件 -e是否存在 then echo "文件可读" else echo "文件不可读" fi ############################# 流程控制 ################################### # 单if语句可以写成一行, 用;隔开,但也必须有fi结尾 if [ $(ps -ef | grep -c "ssh") -gt 1 ]; then echo "true"; fi # 查找当前系统中有多少个ssh进程 # 中间如果有多个判断用 elif ## read 用于从控制台读取输入. #!/bin/bash read -p "please input your name: " NAME if [ $NAME = root ] then echo "hello ${NAME}, welcome!" elif [ $NAME = itcast ] then echo "hello ${NAME}, Wlcm" else echo "SB, get out here." fi #### 注意空格不能少. ######## for循环,有几种写法 for N in 1 2 3; do echo $N; done #一句写完,循环3次 for N in {1..5}; do echo $N; done #一句写完,循环5次 for((i=0;i<=5;i++));do echo "welcome $i times"; done #和其它语言相近的写法. #或者: for((i=0;i<=5;i++)) do echo "welcome $i times" done
# 例如 读取文件:
for LINE in `cat /opt/dbs.txt`
do
/mongodb/bin/mongodump -d $LINE -o /data/backup/
done
####### while #!/bin/bash i=1 while((i<=3)) do echo $i let i++ # let是bash中用于计算的工具,变量计算中不需加$ done ####### case #!/bin/bash echo '输入1到4之间的数字:' read aNum case $aNum in 1) echo '你选择了1' ;; 2) echo '你选择了2' ;; 3) echo '你选择了3' ;; 4) echo '你选择了4' ;; *) echo '你没有输入1到4之间的数' ;; esac #注意分支的半括号和双分号. ############################# 函数 ########################################## #函数必须在使用前定义, 函数名前面可以省略function. #参数返回,可加return,如果不加,会将最后一条命令的结果作为返回值. return后跟数值(0-255) #调用时直接写函数名即可. #!/bin/bash #fun2.sh funWithReturn(){ echo "此函数会对输入的两个数进行相加运算..." echo "输入第一个数:" read aNum echo "输入第二个数:" read bNum echo "两个数分别为 $aNum 和$bNum " return $(($aNum + $bNum)) } #funWithReturn #echo "两数之和为: $?" #!/bin/bash #caller.sh . /test/fun2.sh #跨脚本调用函数 funWithReturn ####### 函数传参 #!/bin/bash funWithParam(){ echo "第一个参数为 $1 " echo "第二个参数为 $2 " a=$4 b=$9 echo $(($a + $b)) echo "第10个参数为 $10 " echo "第十个参数为 ${10} " echo "第十一个参数为 ${11} " echo "参数总共有 $# " echo "作为一个字符串输出所有参数 $* " } funWithParam 1 2 3 4 5 6 7 8 9 34 73
模拟上传log文件到HDFS的shell示例:
假设logs/log/ 下的access.log文件是正在采集中的日志. 而后面带有数字的 access.log.1 文件是前一天的日志文件.
这个shell要做的是将前一天的日志都上传到hdfs上去. 如果结合crontab 就可以实现定时上传.
upload2hdfs.sh 文件:
#!/bin/bash #set java env export JAVA_HOME=/usr/local/src/jdk1.8.0_161 export JRE_HOME=${JAVA_HOME}/jre export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib export PATH=${JAVA_HOME}/bin:$PATH #set hadoop env export HADOOP_HOME=/usr/local/src/hadoop-2.7.5 export PATH=${HADOOP_HOME}/bin:${HADOOP_HOME}/sbin:$PATH #日志文件存放的目录 log_src_dir=/root/logs/log/ #待上传文件存放的目录 log_toupload_dir=/root/logs/toupload/ #日志文件上传到hdfs的根路径 date1=`date -d last-day +%Y_%m_%d` hdfs_root_dir=/data/clickLog/$date1/ #打印环境变量信息 echo "envs: hadoop_home: $HADOOP_HOME" #读取日志文件的目录,判断是否有需要上传的文件 echo "log_src_dir:" $log_src_dir ls $log_src_dir | while read fileName do if [[ "$fileName" == access.log.* ]]; then date=`date +%Y_%m_%d_%H_%M_%S` #将文件移动到待上传目录并重命名 #打印信息 echo "moving $log_src_dir$fileName to $log_toupload_dir"xxxxx_click_log_$fileName"$date" mv $log_src_dir$fileName $log_toupload_dir"xxxxx_click_log_$fileName"$date #将待上传的文件path写入一个列表文件willDoing echo $log_toupload_dir"xxxxx_click_log_$fileName"$date >> $log_toupload_dir"willDoing."$date fi done #找到列表文件willDoing ## grep -v是不包含 ls $log_toupload_dir | grep will | grep -v "_COPY_" | grep -v "_DONE_" | while read line do #打印信息 echo "toupload is in file:"$line #将待上传文件列表willDoing改名为winllDoing_COPY_ mv $log_toupload_dir$line $log_toupload_dir$line"_COPY_" #读列表文件willDoing_COPY_的内容(一个一个的待上传文件名), 此处的line就是列表中的一个待上传文件的path cat $log_toupload_dir$line"_COPY_" | while read line do #打印信息 echo "puting... $line to hdfs path... $hdfs_root_dir" hdfs dfs -mkdir -p $hdfs_root_dir hdfs dfs -put $line $hdfs_root_dir done mv $log_toupload_dir$line"_COPY_" $log_toupload_dir$line"_DONE_" done
假设hdfs在正常运行, 本地执行:
cd /root mkdir -p logs/log vim upload2hdfs.sh # 将代码贴上, 检查各路径是否正确. 保存退出. chmod 755 ./upload2hdfs.sh # 给予执行权限. ./upload2hdfs.sh #等待成功执行完成后, 检查hdfs上是否有刚上传的文件.
实际案例:logstate.sh脚本 结合 crontab 定时重开日志文件:
#!/bin/bash #Rotate the MongoDB logs to prevent a single logfile from consuming too much disk space. app=mongod mongodPath=/data/mongo4.2.0/bin pidArray=$(/usr/sbin/pidof $mongodPath/$app) for pid in $pidArray;do if [ $pid ] then kill -SIGUSR1 $pid fi done
如果没有root权限,而crontab执行的命令中又需要sudo 则可以:
sudo crontab -u root -e
sudo crontab -u root -l
注意:crond进程如果多个,会造成crontab被执行多次的情况。
sudo 碰到重定向 > 时,权限不足。可以使用 sh -c :
sudo sh -c "echo a > 1.txt"
案例:遍历子目录和文件:
参考了:https://blog.csdn.net/weixin_30426065/article/details/97835222
和 https://blog.csdn.net/ts1011/article/details/9119119
和 https://www.cnblogs.com/chengmo/archive/2010/10/02/1841355.html
#!/bin/bash echo $(date +"%F %T.%N" | cut -b 1-23) "check start" function getfiles(){ for file in `ls $1` do if [ -d $1"/"$file ] then echo 'checking... ' $file getfiles $1"/"$file else local path=$1$file # 拼接子目录与文件名 # local name=$file local res=`sha1sum $1"/"$file |awk '{print $1}'` # 计算实际文件的 sha1 # local size=`du --max-depth=1 $path|awk '{print $1}'` # echo $name $size $path if [ ${path#./test/} != $res ] then echo 'not ok' ${path#./test/} $res fi fi done } IFS=$'\n' #这个必须要,否则会在文件名中有空格时出错 INIT_PATH="./test"; getfiles $INIT_PATH echo $(date +"%F %T.%N" | cut -b 1-23) "finished."