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 *** 


### 关闭防火墙
service iptables stop  
setenforce 0  
chkconfig iptables off
View Code

常用命令与工具:

######################################### 资源 情况 ####################
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 

压缩解压:

# 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/ 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

定时任务:


#################################  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分钟


# 不要忘记开启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/$/ /'?
: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组
 exit

lvextend -L +12G /dev/mapper/centos-root  # 也可以按M单位增加也可执行多次,只要pvdisplay中还有 Free PE

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

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://www.cnblogs.com/frx9527/p/bash.html