Shell 应用程序

包管理

apt

  • install
  • update
  • remove
  • autoremove
  • clean

rpm

yum

说明

  • yum在不使用yum makecache手动检查源配置文件时,可能 很长时间都不会更新cache,也就无法发现软件仓库的更新 (当然,可能和仓库类型有关,使用ISO镜像作为仓库时如此, 即使不挂载镜像,yum在执行其他操作也不会发现有个仓库无法 连接)

dpkg

zypper

pacman

库、依赖

ldconfig

创建、查看动态链接库缓存

  • 根据/etc/ld.so.conf文件中包含路径,搜索动态链接库文件 ,创建缓存文件/etc/ld.so.cache

  • 默认包含/lib/lib64/usr/lib/usr/lib64, 优先级逐渐降低,且低于/etc/ld.so.conf中路径

参数

  • 生成动态链接库缓存,并打印至标准输出
  • -v/--verbose:详细版
  • -n:仅扫描命令行指定目录
  • -N:不更新缓存
  • -X:不更新文件链接
  • -p:查看当前缓存中库文件
  • -f CONF:指定配置文件,默认/etc/ld.so.conf
  • -C CACHE:指定生成缓存文件
  • -r ROOT:指定执行根目录,默认/(调用chroot实现)
  • -l:专家模式,手动设置
  • -f Format/--format=Format:缓存文件格式
    • ld:老格式
    • new:新格式
    • compat:兼容格式

ldd

查看程序所需共享库的bash脚本

  • 通过设置一系列环境变量,如LD_TRACE_LOADED_OBJECTSLD_WARNLD_BIND_NOWLD_LIBRARY_VERSIONLD_VERBOSE

  • LD_TRACE_LOAD_OBJECTS环境变量不空时,任何可执行程序 运行时只显示模块的依赖,且程序不真正执行

  • 实质上是通过ld-linux.so实现

    1
    2
    3
    $ /lib/ld-linux.so* --list exe
    $ ldd exe
    // 二者等价
    • ld-linux.so*参见cppc/func_lib.md

参数

  • -v:详细模式
  • -u:打印未使用的直接依赖
  • -d:执行重定位,报告任何丢失对象
  • -r:执行数据、函数重定位,报告任何丢失的对象、函数

打印

  • 第1列:程序动态链接库依赖
  • 第2列:系统提供的与程序需要的库所对应的库
  • 第3列:库加载的开始地址
  • 首行、尾行可能是两个由kernel向所有进程都注入的库

strings

查看系统glibc支持的版本

objdump

查看目标文件的动态符号引用表

Shell 系统监控

系统监控

scar

收集、报告、保存系统活动信息

iostat

报告CUP统计数据,设备、分区输入/输出信息

iotop

I/O监控

mpstat

报告CPU相关统计数据

vmstat

报告虚拟内存统计

tload

加载显示系统平均负载、指定tty终端平均负载

time

显示资源资源使用时间

uptime

显示系统已运行时间

ipcs

提供IPC设施信息

ipcrm

删除消息队列、信号量集、共享内存ID

lslk

列出本地锁

Shell 任务

定时任务

atq

列出用户等待执行的作业

atrm

删除用户等待执行的作业

watch

定期执行程序

at

设置在某个时间执行任务

1
2
3
4
5
6
7
at now+2minutes/ now+5hours
# 从现在开始计时
at 5:30pm/ 17:30 [today]
# 当前时间
at 17:30 7.11.2018/ 17:30 11/7/2018/ 17:30 Nov 7
# 指定日期时间
# 输入命令之后,`<c-d>`退出编辑,任务保存

crontab

针对用户维护的/var/spool/cron/crontabs/user_name文件,其中 保存了cron调度的内容(根据用户名标识)

  • -e:编辑
  • -l:显示
  • -r:删除

任务计划格式见文件部分

任务、作业

Crontab文件

/var/spool/cron/crontabs/user_name

使用用户名标识的每个用户的定时任务计划文件,文件中每行为一个 cron调度内容(也可以使用crontab -e直接编辑)

  • 共6个字段,前5个字段为执行调度时间分配

    • 分钟、小时(24)、日期(31)、月份(12)、星期
    • *表示每个当前时间
    • -时间区间
    • ,时间分隔
    • [range]/[n]:范围内每隔多久执行一次,范围为*可省
  • 最后字段为调度内容

  • 1
    2
    3
    4
    3,15 8-11 */2 * * command
    # 每隔两天的8-11点第3、15分执行
    3,15 8-11 * * 1 command
    # 每个星期一的上午8-11点的第3、15分钟执行

/etc/crontabs

系统级crontab文件,类似于用户crontab文件,只是多一个用户名 字段位于第6个

服务

系统服务

  • 服务systemctl脚本目录优先级从低到高

    • [/usr]/lib/systemd/system:系统、应用默认存放位置 ,随系统、应用更新会改变

    • /etc/systemd/system推荐在此自定义配置,避免 被更新覆盖

      1
      2
      .include /lib/systemd/system/<service_name>.service
      # customized changes
    • /run/systemd/system:进程运行时创动态创建服务文件 目录,仅修改程序运行时参数才会修改

  • 自定义系统服务方法

    • 创建<service_name>.service文件,其中写入配置
    • 创建<service_name>.service.d目录,其中新建.conf 文件写入配置
  • 系统服务控制命令systemctl参见linux/shell/cmd_sysctl

.service

<some_name>.service:服务配置unit文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
[Unit]					# 包含对服务的说明
Description= # 服务简单描述
Documentation= # 服务文档
Requires= # 依赖unit,未启动则当前unit启动失败
Wants= # 配合unit,不影响当前unit启动
BindsTo= # 类似`Requires`,若其退出则当前unit
# 退出
Before= # 若该字段指定unit要启动,则必须在
# 当前unit之后启动
After= # 若该字段指定unit要启动,则必须在
# 当前unit之前启动
Conflicts= # 冲突unit
Condition= # 条件,否则无法启动
Assert= # 必须条件,否则启动失败


[Service] # 服务具体运行参数设置,仅
# *service unit*有该字段
Type= # 服务启动类型
PIDFile= # 存放PID文件路径
RemainAfterExit= # 进程退出后是否认为服务仍处于激活

ExecStartPre= # 服务启动前执行的命令
ExecStartPost= # 服务启动后执行的命令
ExecStart= # 服务具体执行、重启、停止命令
ExecReload=
ExecStop=

Restart= # 重启当前服务的情况
RestartSec= # 自动重启当前服务间隔秒数
TimeoutSec= # 停止当前服务之前等待秒数

PrivateTmp= # 是否给服务分配临时空间
KillSignal=SIGTERM
KillMode=mixed

Environmen= # 指定环境变量

[Install]
WantedBy= # unit所属的target,`enable`至相应
# target
RequiredBy= # unit被需求的target
Alias= # unit启动别名
Also= # `enable`当前unit时,同时被`enable`
# 的unit
  • Type:服务启动类型

    • simple:默认,执行ExecStart启动主进程

      • Systemd认为服务立即启动
      • 适合服务在前台持续运行
      • 服务进程不会fork
      • 若服务要启动其他服务,不应应该使用此类型启动,
    • forking:以fork方式从父进程创建子进程,然后父进程 立刻退出

      • 父进程退出后Systemd才认为服务启动成功
      • 适合常规守护进程(服务在后台运行)
      • 启动同时需要指定PIDFile=,以便systemd能跟踪 服务主进程
    • oneshot:一次性进程

      • Systemd等待当前服务退出才继续执行
      • 适合只执行一项任务、随后立即退出的服务
      • 可能需要同时设置RemainAfterExit=yes,使得 systemd在服务进程推出后仍然认为服务处于激活状态
    • notify:同simple

      • 但服务就绪后向Systemd发送信号
    • idle:其他任务执行完毕才会开始服务

    • dbus:通过D-Bus启动服务

      • 指定的BusName出现在DBus系统总线上时,Systemd 即认为服务就绪
  • WantedBy:服务安装的用户模式,即希望使用服务的用户

    • multi-user.target:允许多用户使用服务

.target

<some_name>.target:可以理解为系统的“状态点”

  • target通常包含多个unit

    • 即包含需要启动的服务的组
    • 方便启动一组unit
  • 启动target即意味将系统置于某个状态点

  • target可以和传统init启动模式中RunLevel相对应

    • 但RunLevel互斥,不能同时启动

    |RunLevel|Target| |——-|——-| |0|runlevel0.targetpoweroff.target| |1|runlevel1.targetrescue.target| |2|runlevel2.targetmulti-user.target| |3|runlevel3.targetmulti-user.target| |4|runlevel4.targetmulti-user.target| |5|runlevel5.targetgraphical.target| |6|runlevel6.targetreboot.target|

  • enable设置某个服务自启动,就是在服务配置.serviceWantedByRequiredBy指明的target注册

    • WantedBy向target对应目录中 /etc/systemd/system/<target_name>.target.wants 添加符号链接
    • RequiredBy向target对应目录中 /etc/systemd/system/<target_name>.target.required 添加符号链接
    • systemctl disable <unit>就是移除对应symlink

.socket

日志

/etc/systemd/journal.conf

Systemd日志配置文件

Systemd(服务)

  • Systemd作为新系统管理器,替代service更加强大

    • 支持服务并行启动,提高效率
    • 具有日志管理、快照备份和恢复、挂载点管理
    • 包括一组命令
  • Systemd可以管理所有系统资源,不同资源统称为Unit

    • service unit:系统服务
    • target unit:多个unit构成的组
    • devie unit:硬件设备
    • mount unit:文件系统挂载点
    • automount unit:自动挂载点
    • path unit:文件、路径
    • scope unit:不是由Systemd启动外部进程
    • slice unit:进程组
    • snapshot unit:Systemd快照,可以切换某个快照
    • socket unit:进程间通信socket
    • swap unit:swap文件
    • timer unit:定时器
  • unit配置文件状态(无法反映unit是否运行)

    • enabled:已建立启动链接
    • diabled:未建立启动链接
    • static:配置文件没有[Install]部分,只能作为 其他unit配置文件依赖,不能独立注册
    • masked:被禁止建立启动链接
  • systemd进程ID为1,掌管所有进程
  • unit配置文件参见linux/shell/config_files

systemctl

  • systemctl通过d-bus和systemd交流,在docker和wsl中可能 没有systemd-daemon,此命令可能不能使用,使用service 代替

查看服务、系统状态

  • status <unit>:查看系统、unit(服务)状态
    • -H <host>:查看远程主机unit状态
  • show <unit>:查看unit底层参数
    • -p <attr>:查看某个具体属性参数
  • 三个查询状态的简单方法,方便脚本使用
    • is-active <serivce>
    • is-failed <serivce>
    • is-enabled <serivce>
  • reset-failed <unit>:清除错误状态

  • list-units:列出所有已加载unit

  • list-unit-files:列出所有系统中unit配置文件、状态
    • --type=:指定特定类型文件
    • --status=:指定特定状态文件
  • list-dependencies <unit>:查看依赖关系
    • -all:展开target类型

状态点/启动级别

  • get-default:查看默认target
  • set-default <target>:设置默认target
  • isolate <target>:切换target,其他target的unit将 被停止

设置服务、系统

  • start <service>:启动服务
  • stop <service>:关闭服务
  • enable <service>:开机自启动服务

    • 行为参见linux/shell/config_files
  • disable <service>:关闭开机自启动服务

    • enable启动后的服务仅仅disable不会立刻停止服务
  • kill <service>:杀死服务的所有子进程
  • mask <service>:禁用服务
    • 无法通过startrestart启动服务
    • 可以防止服务被其他服务间接启动
  • umask <service>:启用已禁用服务
  • daemon-reload:重新读取所有服务项
    • 修改、删除、添加服务项后执行该命令
  • poweroff:关机
  • reboot:重启
  • rescue:进入rescue模式

配置文件

  • cat <service_name>.service:查看Unit定义文件
  • edit <service_name>.service:编辑Unit定义文件
  • reload <service_name>.service:重新加载Unit定义文件

journalctl

journalctl:统一管理所有日志:内核日志、应用日志

  • -k:仅内核日志
  • --since:指定日志时间
  • -n:指定查看日志行数
  • -f:最新日志
  • _PID=:进程日志
  • _UID=:用户日志
  • -u:unit日志
  • -p:日志有限集
    • emerg:0
    • alert:1
    • crit:2
    • err:3
    • warning:4
    • notice:5
    • info:6
    • debug:7
  • --nopager:非分页输出
  • -o:日志输出格式
    • json
    • json-pretty
  • --disk-usage:日志占用空间
  • --vacuum-size=:指定日志占用最大空间
  • --vacuum-time=:指定日志保持时间

systemd-analyze

systemd-analyze:查看系统启动耗时

  • blame:查看各项服务启动耗时
  • critical-chain:瀑布状启动过程流

hostnamectl

hostnamectl:查看主机当前信息

  • set-hostname <hostname>:设置主机名称

localectl

localctl:查看本地化设置

  • set-locale LANG=en_GB.utf8
  • set-keymap en_GB

timedatectl

timedatectl:查看当前时区设置

  • list-timezones:显示所有可用时区
  • set-timezone America/New_York
  • set-time YYYY-MM-DD
  • set-time HH:MM:SS

loginctl

loginctl:查看当前登陆用户

  • list-sessions:列出当前session
  • list-users:列出当前登陆用户
  • show-user <user>:显示用户信息

service

控制系统服务

Shell 用户配置

用户、组

用户信息

/etc/passwd

用户属性

  • 用户名
  • 口令:在/etc/passwd文件中以x显示
  • user-id:UID,用户标识
    • linux事实上不直接处理用户名,只识别UID
    • UID对用户是唯一的
  • group-id:GID,用户的默认组标识
    • 用户可以隶属多个不同的组,但是只有一个默认组,即用户 创建文件默认隶属的组
  • 描述:用户描述
  • 用户主目录:用户登陆目录
  • 登陆shell:用户登陆系统使用的shell
    • 缺省为空,可能是/bin/sh

/etc/shadow

用户口令属性

  • 用户名
  • 加密的密码
  • 自1/1/1970起,密码被修改的天数
  • 密码将被允许修改之前的天数(0为在任何时候可修改)
  • 系统强制用户修改为新密码之前的天数(1永远不能修改)
  • 提前警告用户密码过期前天数(-1无警告)
  • 禁用用户账户在密码过期后天数(-1永不禁用)
  • 用户被禁用天数(-1被启用)

/etc/group

群组账号信息文件

  • 群组名
  • 密码:以x显示
  • 群组ID(GID)
    • 系统群组:安装Linux以及部分服务型程序时自动设置的 群组,GID<500
    • 私人组群:由root新建的群组,默认GID>500
  • 附加用户列表

/etc/gshadow

群组口令信息文件

/etc/sudoers

sudo配置文件

  • 根据配置文件说明取消注释即可赋予用户、组sudo权限

用户配置文件

  • login-shell:用户登陆(创建session)时的shell模式,该 模式下shell会自动执行profile文件
  • subshell:用户登陆后载入的shell的模式,该模式下shell会 自动执行rc文件

profile

-一般在login-shell模式会执行一次,从名称看起来更像是 用户配置

  • 全局、被所有用户默认执行的文件在/etc目录下,用户个人 profile在用户目录

  • ^profile$是所有类型shell(bash、zsh、ash、csh)都会 执行

  • 不同类型的shell可能有其特定的profile文件,如: /etc/bash_profile~/.bash_profile,不过不常见 (可以理解,毕竟是用户配置

  • 有的发行版本(ubuntu)还有有/etc/profile.d文件夹,在 /etc/profile中会设置执行其中的配置文件

rc

rc应该是run command的简称,在每次subshell模式会执行,从 名称看起来更像是shell配置(很多应用配置文件rc结尾)

  • 全局、被所有用户执行的文件在/etc目录下,用户个人rc 则在用户目录

  • 应该是因为rc本来就是对shell的配置文件,所以是不存在 通用的^rc$配置的,最常用的bash对应就是~/.bashrc~/bash.bashrc

总结

  • 其实rc也会在用户登陆时执行

    • login-shell会立刻载入subshell?
    • profile里设置了立刻调用?
  • 应该写在profile里的配置

    • shell关系不大、更像是用户配置,如:特定应用环境变量
    • 不需要、不能重复执行,因为rc在用户登录时已经执行 过一次,launch subshell时会重复执行,如: export PATH=$PATH:xxxx/bin/
  • 应该写在rc里的配置

    • 和shell关系紧密的shell配值,如:alias
    • 在用户登陆后会该边,需要在每次launch subshell时执行 的配置
  • 配置文件执行顺序

    • 没有一个确定顺序,不同的linux发行版本有不同的设置, 有的还会在脚本中显式写明相互调用,如:/etc/profile 中调用/etc/bashrc~/.bashrc调用/etc/bashrc
    • 但是可以确认的是/etc/profile一般是第一个被调用, ~/.xxxxrc/etc/xxxxxrc中的一个最后调用
  • 还有一些其他配置文件

    • ~/.bash_logout:退出bash shell时执行
  • 对于wsl,可能是因为将用户登陆windows视为create session, ~/.profile好像是不会执行的

/etc/environment

系统在登陆时读取第一个文件

  • 用于所有为所有进程设置环境变量
  • 不是执行此文件中的命令,而是根据KEY=VALUE模式的 代码,如:PATH=$PATH:/path/to/bin

用户命令

用户类型

  • 超级用户:root用户
  • 系统用户:与系统服务相关的用户,安装软件包时创建
  • 普通用户:root用户创建,权限有限

显示登陆用户

w

详细查询已登录当前计算机用户

who

显示已登录当前计算机用户简单信息

logname

显示当前用户登陆名称

users

用单独一行显示当前登陆用户

last

显示近期用户登陆情况

lasttb

列出登陆系统失败用户信息

lastlog

查看用户上次登陆信息

用户、用户组

newusers

更新、批量创建新用户

lnewusers

从标准输入中读取数据创建用户

userdel

删除用户账户

groupdel

删除用户组

passwd

设置、修改用户密码

chpassws

成批修改用户口令

change

更改用户密码到期信息

chsh

更改用户账户shell类型

pwck

校验/etc/passwd/etc/shadow文件是否合法、完整

grpck

验证用户组文件/etc/grous//etc/gshadow完整性

newgrp

将用户账户以另一个组群身份进行登陆

finger

用户信息查找

groups

显示指定用户的组群成员身份

id

显示用户uid及用户所属组群gid

su

切换值其他用户账户登陆

sudo

以superuser用户执行命令

  • Archlinux中需要自行安装
  • 配置文件为/etc/sudoers

useradd/adduser

创建用户账户(adduseruseradd命令的符号链接)

  • -c:用户描述
  • -m:创建用户目录
  • -d:用户起始目录
  • -g:指定用户所属组
  • -n:取消建立以用户为名称的群组
  • -u:指定用户ID
  • -s:指定用户登录shell
    • 缺省为空,默认值应该是/bin/sh,很多发行版会设置 其为/bin/bash
    • 查看$SHELL环境变量查看当前shell
    • 文件/etc/shells包含支持shell类型

usermod

修改用户

  • -e:账户有效期限
  • -f:用户密码过期后关闭账号天数
  • -g:用户所属组
  • -G:用户所属附加组
  • -l:用户账号名称
  • -L:锁定用户账号密码
  • -U:解除密码锁定

groupadd

新建群组

  • -g:强制把某个ID分配给已经存在的用户组,必须唯一、非负
  • -p:用户组密码
  • -r:创建系统用户组

groupmod

  • -g:设置GID
  • -o:允许多个用户组使用同一个GID
  • -n:设置用户组名

Pywin32 接口

说明

  • pywin32 包是对 windows 提供接口的封装,和 C/CPP 接口内容相近

win32api

Shell

  • win32api.ShellExecute(hwnd, op, file, params, dir, bShow)
    • hwnd:父窗口句柄
    • op:操作,"open""print"
    • file:需要执行操作的文件
    • params:待执行操作的文件为可执行文件时,需要传递的参数
    • dir:应用执行的初始文件夹
    • bShow:应用打开时是否展示

Keyboard

  • win32api.keybd_event(bVk, bScan, dwFlags, dwExtraInfo) )
    • bVk:虚拟键码,可通过 win32con.VK_<KEY> 获取
    • bScan:硬件扫描码,一般设置为 0
    • dwFlags:一般设置为 0,表示按键按下
      • win32con.KEYEVENTF_EXTENDEDKEY
      • win32con.KEYEVENTF_KEYUP:按键释放
    • dwExtraInfo:与击键相关的附加的32位值,一般设置为 0

Shell编程基础

变量

定义、使用、删除

  • 定义变量

    • 定义时不加$符号
    • 变量名和等号之间不能有空格
    • 变量名只能由英文字母、数字、下划线,且不以数字开头, 不能用bash中的关键字
    • 已经定义变量可以重新定义
  • 使用变量

    • 即可使用, 未定义变量直接使用不报错,返回空值
    • {}可选,但是{}能够明确定义变量名范围,帮助阅读、 解释器执行
  • 匿名变量

    • 可以认为所以语句(命令)的执行结果都存储在一个匿名 变量中,可以在其之前加上$获取其结果
  • readonly:设置变量为只读变量,更改(重定义)变量报错

  • unset:删除变量,不能删除只读变量

局部变量

局部变量:在脚本、命令中定义

  • 仅在当前shell实例中有效

    • shell变量默认为global,作用域从被定义处开始到脚本 末尾(即使在函数内部定义)
    • 显式local声明作用域局限于函数内部
  • 其他shell启动的程序不能访问局部变量

环境变量

环境变量:就是shell中的普通变量,只是这些变量往往被进程读取 用于自身初始化、设置

  • 狭义:export/declare -x声明的变量,只有这样的变量 才能默认被子进程继承
  • 广义;shell中所有的变量(包括局部变量)

环境变量设置

在shell中设置环境变量有两种方式

  • export/declare -x:设置全局(环境)变量

    • 任何在该shell设置环境变量后,启动的(子)进程都会 继承该变量
    • 对于常用、许多进程需要的环境变量应该这样设置
  • <ENV_NAME>=... cmd:设置临时环境变量

    • <ENV_NAME>=...不能被子进程继承,所以必须在其后立刻 接命令
    • 只对当前语句有效,也不能覆盖同名变量

用途

  • 环境变量是某些程序正常运行的必要条件
  • 所有程序都能访问环境变量,可用作进程通信
    • 在程序中设置环境变量,供其他进程访问变量
    • 父进程为子进程设置环境变量,供其访问

Shell变量

Shell变量:shell程序设置的特殊变量,包括环境变量、局部变量, 保证shell的正常运行

  • $0:shell执行脚本名

    • 交互式bash(即普通终端中)该参数为-bash
      • source执行脚本时,该参数可能非预期
    • 以下shell变量均不考虑$0,如
      • 函数中$0也是脚本名
      • shift无法跳过该参数
  • $1,..., $9:向脚本传递的位置参数

  • $@:脚本、函数参数列表
  • $*:脚本、函数参数字符串
  • $#:脚本、函数参数数量
  • $?:上条命令执行结果
  • $$$$:脚本进程号
  • $!:执行脚本最后一条命令

字符串

拼接

  • shell中字符默认为字符串,自动拼接

通配符

  • *:匹配任意长度字符串

    • 不包括./,必须显式匹配
  • ?:匹配一个字符

  • []:匹配出现在[]中的字符

    1
    2
    ls /[eh][to][cm]*
    # 匹配`/etc`、`/home`等
  • {}

    • 枚举全部

      1
      2
      3
      4
      5
      6
      $ mkdir {user1, user2}-{home, bin}
      # 笛卡尔积(字符串连接)
      # 等价于建立`user1-home, user1-bin, user2-home, user2-bin`
      $ echo {1..10}
      # 生成序列
      # 见`for`中`RangeIterator`部分

子串

1
2
$ file=/dir1/dir2/dir3/file.txt.bak
$ null=""

切片

  • ${<var_name>:n[:m]}:从第n开始m个字符
    • nm非负值
      • n:从0开始的下标起始
      • m切片长度缺省表示到末尾
    • nm使用0-负值表示
      • n:从0开始的负向下标起始
      • m:从0开始的负向下标终止
命令 解释 结果
${file:0:5} 提取首个字符开始的5个字符 /dir1
${file:5:5} 提取第5个字符开始的5个字符 /dir2
${file:5} 提取第5个字符开始至末尾 /dir2...
${file:0-5} 反向计算下标 t.bak
${file:0-5:0-1} 反向计算下标 t.ba
${file:5:0-2} 提取第5个字符开始至-2下标处 /dir2.../t.b

子串匹配

1
2
3
4
${<var_name>%<pattern>}
${<var_name>%%<pattern>}
${<var_name>#<pattern>}
${<var_name>##<pattern>}
  • #:去掉字符串左边最短pattern
  • ##:去掉字符串左边最长pattern
  • %:去掉字符串右边最短pattern
  • %%:去掉字符串右边最长pattern
  • 注意:var_name前不要变量标志$
  • 以上4种模式返回新值,不改变原变量值
  • 仅在pattern中使用通配符时,最短、最长匹配才有区别
命令 解释 结果
${file#*/} 去除首个/及其左边 dir2/dir3/file.txt.bak
${file##*/} 仅保留最后/右边 file.txt.bak
${file#*.} 去除首个.及其左边 txt.bak
${file##*.} 仅保留最后.右边 bak
${file%/*} 去除最后/及其右边 /dir1/dir2/dir3
${file%%*/} 去除首个/及其右边 空值
${file%*.} 去除最后.及其右边 /dir1/dir2/dir3/file.txt
${file%%*.} 去除首个.及其右边 /dir1/dir2/dir3/file.txt

替换

  • /from/to:替换首个fromto
  • //from/to:替换全部fromto
命令 解释 结果
${file/dir/path} 替换首个dirpath /path1/dir2/dir3/file.txt.bak
${file/dir/path} 替换全部dirpath /path1/path2/path3/file.txt.bak

默认值替换

  • -:变量未设置返回
  • +:变量设置返回
  • =:变量未设置返回、设置变量
  • ?:变量未设置输出至stderr
  • ::以上命令条件包括空值(空值视为未设置)

shell_variable_assignment

命令 解释 示例 结果
${井<var_name>} 获取字符串长度 ${井file} 27
${<var_name>-<default>} 变量未设置返回默认值 ${invalid-file.txt.bak} file.txt.bak
${<var_name>:-<default>} 变量未设置、空值返回默认值 ${null-file.txt.bak} file.txt.bak
${<var_name>+<default>} 变量设置返回默认值 ${file-file.txt.bak} fil.txt.bak
${<var_name>:+<default>} 变量非空返回默认值 ${file-file.txt.bak} file.txt.bak
${<var_name>=<default>} 变量未设置,返回默认值、并设置变量为默认值 ${invalid=file.txt.bak} file.txt.bak
${<var_name>:=<default>} 变量未设置、空值返回默认值、并设置变量为默认值 ${null=file.txt.bak} file.txt.bak
{$<var_name>?<default>} 变量未设置输出默认值至stderr {invalid?file.txt.bak} file.txt.bak输出至stderr
{$<var_name>:?<default>} 变量未设置、空值输出默认值至stderr {$null:?file.txt.bak} file.txt.bak输出至stderr

字符串比较

  • =, !=, -z, -n:字符串相等、不相等、为空、非空

  • 使用=比较变量是否为某字符串时,其中在两侧添加字符 保证=不为空值,否则若$test为空值,表达式报错

    1
    2
    3
    if [[ "$text"x = "text"x ]]; then
    command
    fi
  • 比较变量时要在两侧加上双引号"",否则可能报错、结果不 符合预期

数组

1
$ A=(a b c def)

取值

  • []:选择数组元素
    • [n]:返回数组第n个元素
    • [*]/[@]:返回数组全部元素
命令 解释 结果
${A[@]} 返回全部元素 a b c def
${A[*]} 同上 同上
${A[0]} 返回数组第一个元素 a
${井A[@]} 返回数组元素总数 4
${井A[*]} 同上 同上
${井A[3]} 返回数组第4个元素长度 3
A[3]=xyz 设置数组第4个元素值

数值

  • (())/[]:在其中执行整数运算
  • let:执行数值运算

规则

  • 返回的数据结果相当于存储在一个匿名变量中,使用的话需要 在之前加上$

  • 1
    2
    3
    $ a=5; b=7; c=2;
    $ echo $((a + b * $c))
    # 19
  • $((N#xx))/$[$#xx]:将其他进制数据转换为10进制

    1
    2
    $ echo $((2#110))
    # 6
  • 自增、自减运算可以在(())/[]中直接执行

    1
    2
    $ a=5; ((a++)); echo $a;
    # 6

特殊运算符

  • ~:位与
  • |:位或
  • ^:位异或
  • >>:位右移
  • <<:位左移
  • **:数值平方
  • +=, ++, -=, --, *=, \=:自变化运算符

逻辑运算

  • -eq, -ne, -ge, -le, -lt, -gt:比较
  • ==, !=, >=, <=, <, >:数值比较

文件

  • -e:目标存在
  • -f:文件为一般文件(非目录、设备)
  • -s:文件大小非0
  • -d:目标为目录
  • -b:文件为块设备(软盘、光驱)
  • -c:文件为流设备(键盘、modem、声卡)
  • -p:文件为管道
  • -h/L:目标为符号链接
  • -S:目标为Socket
  • -t:文件描述符被关联到终端
    • 一般用于检测脚本的stdin是否来自终端[ -t 0 ],或 输出是否输出至终端[ -t 1 ]
  • -r:目标是否可读权限
  • -w:目标是否可写权限
  • -x:目标是否可执行权限
  • -g:目标是否设置有set-group-id
  • -u:目标是否设置有set-user-id
  • -k:目标是否设置sticky bit
  • -O:用户是否是文件所有者
  • -G:用户是否属于文件所有组
  • -N:文件从上次读取到现在为止是否被修改
  • f1 -nt f2:文件f1f2
  • f1 -ot f2:文件f1f2
  • f1 -ef f2:文件f1f2指向相似文件实体(相同的硬链接)

Bash 编程技巧

检查命令是否成功

  • 原版

    1
    2
    3
    4
    5
    6
    7
    echo abcdee | grep -q abcd

    if [ $? -eq 0 ]; then
    echo "found
    else
    echo "not found"
    fi
  • 简洁版

    1
    2
    3
    4
    5
    if echo abcdee | grep -q abc; then
    echo "found"
    else
    echo "not found"
    fi
  • 精简版

    1
    echo abcdee | grep -q abc && echo "found" || echo "not found"

标准输出、错误输出重定向到/dev/null

  • 原版

    1
    $ grep "abc" text.txt 1>/dev/null 2>&1
  • 简洁版

    1
    $ grep "abc" text.txt &> /dev/null

awk使用

  • 原版
    1
    $ sudo xm li | grep vm_name | awk `{print $2}`
  • 简洁版
    1
    $ sudo xm li | awk `/vm_name/{print $2}`

逗号连接所有行

  • 原版:sed

    1
    $ sed ":a;$!N;s/\n/,;ta" test.txt
  • 简洁:paste

    1
    $ paste -sd, /tmp/test.txt

过滤重复行

  • 原版:sort

    1
    $ sort text.txt | unique
  • 简洁版

    1
    $ sort -u text.txt

Bash 脚本执行

脚本执行

#!

脚本首行注释

  • 文件执行时,shell会将文件内容发送至#!之后的解释器上
  • 不限于shell脚本,也适合其他类型的脚本语言
    • 当然要求#为脚本语言支持的注释符
  • 建议在首行使用env命令而不是硬编码解释器路径,这样可以 减少对机器的依赖
    1
    2
    #!/usr/bin/env python
    #!/usr/bin/env shell

4种执行方式

  • $ file_name:表示在当前shell执行文件,需要有文件的执行 权限

  • $ source/. file_namesource.意义一致,表示读取 文件内容在shell中,然后在shell里执行文件内容,需要读权限

  • $ sh file_name:表示开启一个新的shell进程,并读取文件 内容在新的shell中然后执行,同样的需读权限

以下面的文件test.sh为例

1
2
3
4
5
#!/bin/bash
echo "fisrt"
sleep 1000
echo "second"
slepp 1000
  • $ test.sh:产生两个新进程test.sh和sleep,在second输出 之前<ctrl-c>,会同时终止两个进程,不会继续输出second

  • $ sh test.sh:产生两个新进程,shell和sleep,在second 输出之前<ctrl-c>,同样的会同时终止两个进程,不会继续 输出second(实际上first是在新的shell里输出的)

  • source/. test.sh:产生一个新进程sleep,在second输出之前 <ctrl-c>,只有sleep进程被终止,而test.sh的内容在当前 shell里直接执行,当前shell没有被终止,second会继续输出

结论

  • 如果需要对当前shell进行设置,应该使用source/.

  • 否则这三种执行方式除了进程产生、权限要求应该没有差别

Shell环境

环境变量

  • 设置环境变量直接:$ ENV_NAME=value=前后不能有空格) 但是此时环境变量只能在当前shell中使用,需要export命令 导出之后才可在子shell中使用

  • 环境变量设置代理

    1
    2
    export http_proxy=socks://ip
    export https_proxy=socks5://ip

输入输出

  • 0:STDIN_FILENO,标准输入
  • 1:STDOUT_FILENO,标准输出
  • 2:STDERR_FILENO,标准错误

说明:

  • 标准输出和标准错误虽然都是在命令行上显示,但是两个是 不同的流。输出重定向>只能将标准输出重定向,不会将 标准错误重定向,其仍然会在命令行显示

重定向

  • <:重定向标准输入
  • >:标准输出write重定向
  • >>:标准输出add重定向
  • 2>:标准错误重定向

说明:

  • 输出重定向就是1 > outputcommand > output只是省略 1的简写

    • 命名自己不是输出,不能重定向
    • 是命令产生的标准输出重定向
  • 可以通过2>&1将标准错误重定向到标准输出,从而将命令的 标准输出、错误输出同时输出

    • &这里表示等效于标准输出(标准输出的引用)
    • command>a 2>acommand>a 2>&1看起来类似,实际上 前者写法会打开两次a,stderr覆盖stdout,而后者是 引用,不会覆盖、IO效率更高
    • 2>&1放在后面大概是因为需要获取stdout的引用,所以 需要标准输出先给出重定向
    • 这种写法还有个简写&>>&
  • 可以重定向到设备,在*nix系统中,设备也被视为文件

    1
    $ echo "hello" > /dev/tty01

    特别的设备/dev/null可以作为不需要输出的重定向目标

HereDoc Format

HereDoc Format:特殊的重定向,指示shell从标准输入读取输入 直至遇到标记行(前后不能有空白符)

1
2
3
<CMD> << <EOF>
here-doc
<EOF>
  • EOF:标记字符串,常用EOFSTOP
  • 若标记中含有字符被quote(如被引号包括)

    • 结束标记为去除quotation结果
    • here-doc中不执行参数扩展、命令替换、算数扩展
  • 若标记中没有quotation

    • here-doc中执行参数扩展、命令替换、算数扩展
    • 此时\$、反引号需要\转义

管道

|:将一个程序的标准输出发送到另一个程序的标准输入

  • 一些平台会并行启动以管道连接的程序,此时使用类似迭代器 输出、输入能提高效率

Shell内置命令

  • which命令无法找到的命令

set

set:设置所使用的shell选项、列出shell变量

  • :不带参数,显示全部shell变量
  • -a:输出之后所有至export(环境变量)
  • -b:使被终止后台程序立即汇报执行状态
  • -B:执行括号扩展
  • -C:重定向所产生的文件无法覆盖已存在文件
  • -d:shell默认使用hash表记忆已使用过的命令以加速 执行,此设置取消该行为
  • -e:若指令回传值不为0,立即退出shell
  • -f:取消使用通配符
  • -h:寻找命令时记录其位置???
  • -H:(默认)允许使用!<编号>方式执行history中 记录的命令
  • -k:命令=被视为设置命令的环境变量
  • -m:监视器模式,启动任务控制
    • 后台进程已单独进程组运行
    • 每次完成任务时显示包含退出的状态行
  • -n:读取命令但不执行
    • 通常用于检查脚本句法错误
  • -p:允许set-user/group-id
    • 禁止处理$ENV文件、从文件中继承shell函数
  • -P:处理cd等改变当前目录的命令时,不解析符号链接
  • -t:读取、执行下条命令后退出
  • -u:使用未设置变量作为错误处理
  • -v:输入行被读取时,显示shell输出行
  • -x:显示简单命令的PS4扩展值(包括所有参数)、当前命令 的环境变量
  • -o:option-name,下列之一
    • allexport:同-a
    • braceexpand shell:(默认)执行花括号扩展
    • emacs:(默认)使用emacs风格命令行编辑接口
    • errexit:同-e
    • errtrace:同-E
    • functrace:同-T
    • hashall:同-h
    • histexpand:同-H
    • history:记录命令历史
    • ignoreeof:读取EOF时不退出shell
    • interactive-comments:允许交互式命令中出现注释
    • keyword:同-k
    • monitor:同-m
    • noclobber:同-C
    • noexec:同-n
    • noglob:同-f
    • noglob:currently accepted but ignored
    • nohash:同-d
    • notify:同-b
    • nounset:同-u
    • physical:同-P
    • pipfail:管道命令返回值为最后返回值非0命令的状态, 若没有非0返回值返回0
    • posix:改变shell属性以匹配标准,默认操作不同于 POSIX1003.2标准
    • priviledged:同-p
    • verbose:同-v
    • vi:使用vi风格的命令编辑接口
    • xtrace:同-x
  • +:加以上参数取消标志位设置(包括o参数)
  • --:给所有剩余参数设置标志位,没有剩余参数则unset
  • -:给所有剩余参数设置标志位
  • $-中存放有当前已设置标志位

let

let:执行计算的工具,用于执行一个、多个表达式

  • 变量计算中不需要$标识变量
  • 表达式中包含特殊字符,需要引起来

declare

declare:声明变量内容

  • -a:声明变量为普通数组
  • -A:声明变量为关联数组(下标支持字符串,类似字典)
  • -i:声明变量为整形
  • -r:声明变量只读
  • -x:设置为环境变量(export
  • -g:在函数中创建全局变量
  • +:和以上联合使用,取消定义的变量类型

  • -f:列出脚本中定义的函数名称、函数体

  • -F:列出脚本中定义的函数名称
  • -p:查看变量属性、值

read

read:从标准输入读入变量内容

1
2
$ read [<option>] <var>[ <var2>...]
$ read -p "Enter names: " name1, nem
  • 读取值数目大于变量数目时,多余值均赋给最后变量
  • -p:命令行提示内容
  • -n:不换行
  • -d:分隔标记
  • -t:阻塞等待时常,之后返回非零
  • -s:隐藏输入
  • -r:反折号不被视为转义标记
1
2
3
cat README | while read -r line; do
echo $line
done

shift

shift:移除参数列表中头部部分参数,缺省移除1个

  • shift移除从$1开始,无法移除$0

getopts

getopts:逐个读取解析单字符指示的参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function func (){
echo OPTIND: $OPTIND
while getopts ":a:B:cdef" opt; do
case $opt in
a) echo "this is -a the arg is ! $OPTARG at $OPTIND" ;;
B) echo "this is -B the arg is ! $OPTARG at $OPTIND" ;;
c) echo "this is -c the arg is ! $OPTARG at $OPTIND" ;;
\?) echo "Invalid option: -$OPTARG" ;;
esac
done
echo OPTIND: $OPTIND
echo $@
shift $(($OPTIND - 1))
echo $@

}
func -a 23 -B 1904-03-04 343 age
  • $OPTARG:参数值
  • $OPTIND:在参数列表中位移,初始值为1,常配合shift 使用剔除已处理参数
  • 遇到未指定option则返回0
  • option字符后::字符可以带有参数,赋给$OPTARG;否则 仅表示标志,仅该字符被处理

  • option_string开头:可以避免错误输出

    • :标记option不带参数时
      • 待匹配值设为:
      • $OPTARG设为option
    • option无效时
      • 待匹配值设为?
      • $OPTARG设为option
  • 函数内部处理函数参数,否则处理脚本参数
  • 参数标识-可省略

Linux 系统启动

登陆、退出、关机、重启

login

登陆系统

logout

退出shell

exit

退出shell(常用)

rlogin

远程登陆服务器

poweroff

关闭系统,并将关闭记录写入/var/log/wtmp日志文件

ctrlaltdel

强制或安全重启服务器

shutdown

关闭系统

halt

关闭系统

reboot

重启系统

init 0/6

关机/重启

Shell 环境变量

环境

export

显示、设置环境变量,使其可在shell子系统中使用

  • 设置环境变量直接$ ENV=value即可,但是此环境变量 不能在子shell中使用,只有$ export ENV导出后才可
  • -f:变量名称为函数名称
  • -n:取消导出变量,原shell仍可用
  • -p:列出所有shell赋予的环境变量

系统环境变量

NAME

  • PATH:用户命令查找目录
  • HOME:用户主工作目录
  • SHELL:用户使用shell
  • LOGNAME:用户登录名
  • LANG/LANGUAGE:语言设置
  • MAIL:用户邮件存储目录
  • PS1:命令基本提示符
  • PS2:命令附属提示符
  • HISTSIZE:保存历史命令记录条数
  • HOSTNAME:主机名称
  • /etc/passwd/etc/hostname等文件中设置各用户部分 默认值,缺省随系统改变

PATH

C PATH

  • LIBRARY_PATH:程序编译时,动态链接库查找路径
  • LD_LIBRARAY_PATH:程序加载/运行时,动态链接库查找路径
  • 动态链接库寻找由/lib/ld.so实现,缺省包含/usr/lib/usr/lib64
    • 建议使用/etc/ld.so.conf配置替代LD_LIBRARY_PATH, 或在编译时使用-R<path>指定
    • 手动添加动态链接库至/lib/usr/lib等中时,可能 需要调用ldconfig生成cache,否则无法找到