shell
A Little Book on Shell
常用 command
- file cp mv mkdir rm ln 其中ln 命令 ln file link, 默认 创建 hard link, ln -s file link 才 为 soft link, soft link 同样增加 file 的link count
- Working with Commands (type which help man apropos info whatis alias)
1
2
3
4
5
6
7
8
9
10
| command | meaning |
|---------|---------------------------------------------------|
| type | Indicate how a command name is interpreted |
| which | Display which executable program will be executed |
| help | Get help for shell builtins |
| man | Display a command's manual page |
| apropos | Display a list of appropriate commands |
| info | Display a command's info entry |
| whatis | Display one-line manual page descriptions |
| alias | Create an alias for a command |
commands 的来源:
- An executable program: 例如 /usr/bin 下面的 可执行文件,
- A command built into the shell itself.: bash 支持的内建 的 命令
- A shell function: shell 函数 Shell functions are miniature shell scripts incorporated into the environment
- An alias: Aliases are commands that we can define ourselves, built from other commands.
man 详细内容: Display a Program’s Manual Page。 手册内容 被分为 几个 章节, 除了 使用 man command, 之外 可以使用 man 1 command 来显示 User commands 章节
section contents 1 User commands 2 Programming interfaces for kernel system calls 3 Programming interfaces to the C library 4 Special files such as device nodes and drivers 5 File formats 6 Games and amusements such as screen savers 7 Miscellaneous 8 System administration commands - apropos – Display Appropriate Commands 展示相关的 命令。通过 apropos ls 可以获得 lscpu, lshw, 等一系列 命令
- whatis – Display One-line Manual Page Descriptions: 展示一行关于 command的简单描述
- info 另一种展现形式的 man
- alias: alias name=’string’ 来构建 名为 name 的command line, type name 可以获得 name 对应的 具体string 内容
Redirection
- cat sort uniq grep wc head tail tee (Read from standard input and write to standard output and files)
- command line 数据流 有: 标准输入 标准输出 标准错误输出,即: stdin, stdout, stderr, 0, 1, 2
- 重定向 stdout, 使用 > 来将 输出 重定向到 file 中,file中内容将被覆盖。 » 将 数据重定向 到file中,不覆盖 追加到 file 末尾中
- 重定向 stderr, 类似 重定向 stdout 使用 2>, 2» 进行 标准错误输出 的数据重定向
- 将stdout & stderr 重定向 到一个 file 中:
- ls -l /bin/usr > ls-output.txt 2>&1 , 注意 其中的 2>&1 的写法,以及, > 与 2>&1 的顺序, 其中原因,为shell 语法需要 控制 两次重定向 打开的是同一个文件
- ls -l /bin/usr &> ls-output.txt 也可以这样 &> 代表 stdout stderr, ls -l /bin/usr &» ls-output.txt 则代表 将stdout stderr 数据流 追加到 文件中
- Disposing of Unwanted Output: ls -l /bin/usr 2> /dev/null 将 数据流 重定向 到 /dev/null 则可以起到忽略 数据流的作用
- 重定向 stdin, 使用 < 来重定向 stdin 从 键盘 到 file 上, 但是并不是特别有用(很少用到)
Pipelines: 使用 pipe operator 将 一个command 的标准输出 输送 到 一个command 的标准输入中。 command1 command2 - Pipelines 与 重定向的 区别: 重定向只能 定向到 file, 而 pipelines 则可以 重定向到 一个command
Seeing the World as the Shell Sees It
扩展 Expansion: how a simple character sequence, for example *, can have a lot of meaning to the shell. The process that makes this happen is called expansion. With expansion, we enter some- thing and it is expanded into something else before the shell acts upon it. 也就是 说 在 传递 参数给 command, command 接收参数处理前,会被 进行处理,该处理过程 即是: expansion。 {}
- echo 是如何 显式化 看到 expansion 结果的 重要方式
Pathname Expansion (路径扩展): 如下释义:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
[me@linuxbox ~]$ ls Desktop ls-output.txt Pictures Templates Documents Music Public Videos [me@linuxbox ~]$ echo D* Desktop Documents [me@linuxbox ~]$ echo *s Documents Pictures Templates Videos [me@linuxbox ~]$ echo [[:upper:]]* Desktop Documents Music Pictures Public Templates Videos [me@linuxbox ~]$ echo /usr/*/share /usr/kerberos/share /usr/local/share
Arithmetic Expansion: $((expression)), expression 是 算术表达式, 操作数 只能是整数, 操作符 有 +, -, *, /, %, **
1
[me@linuxbox ~]$ echo $(($((5**2)) * 3))
Brace Expansion:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
[me@linuxbox ~]$ echo Front-{A,B,C}-Back Front-A-Back Front-B-Back Front-C-Back [me@linuxbox ~]$ echo Number_{1..5} Number_1 Number_2 Number_3 Number_4 Number_5 [me@linuxbox ~]$ echo {01..15} 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 [me@linuxbox ~]$ echo {001..15} 001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 [me@linuxbox ~]$ echo {Z..A} Z Y X W V U T S R Q P ON M L K J I H G F E D C B A [me@linuxbox ~]$ mkdir Photos [me@linuxbox ~]$ cd Photos [me@linuxbox Photos]$ mkdir {2007..2009}-{01..12} [me@linuxbox Photos]$ ls 2007-01 2007-07 2008-01 2008-07 2009-01 2009-07 2007-02 2007-08 2008-02 2008-08 2009-02 2009-08 2007-03 2007-09 2008-03 2008-09 2009-03 2009-09 2007-04 2007-10 2008-04 2008-10 2009-04 2009-10 2007-05 2007-11 2008-05 2008-11 2009-05 2009-11 2007-06 2007-12 2008-06 2008-12 2009-06 2009-12
Parameter Expansion
1 2
[me@linuxbox ~]$ echo $USER me
Command Substitution: 子命令, 允许在表达式中 执行子命令 并展开. $(command sub)
1 2
[me@linuxbox ~]$ echo $(ls) Desktop Documents ls-output.txt Music Pictures Public Templates Videos
- Quoting: 可以用来控制 是否进行 扩展 展开。
下面两个示例:
1 2 3 4 5
[me@linuxbox ~]$ echo this is a test this is a test [me@linuxbox ~]$ echo The total is $100.00 The total is 00.00
注意 这两个 的存在的问题 1. 第一个中 shell 将 params 中多余的空格 去掉了, 即是: ‘a test’中多余的空格, 因为 shell 将 通过 空格 分隔 参数,认为 a test 为两个参数。 2. $100.00 展开为了 00.00 是因为 $1 不存在的缘故
Double Quotes: 将参数 加上 “” 之后, ““内的内容 将被视为 一个 参数, 但 parameter expansion, arithmetic expansion, and command substitution 依然 有效。 如下示例:
1 2 3 4 5 6
[me@linuxbox ~]$ ls -l two words.txt ls: cannot access two: No such file or directory ls: cannot access words.txt: No such file or directory [me@linuxbox ~]$ ls -l "two words.txt" -rw-rw-r-- 1 me me 18 2016-02-20 13:03 two words.txt [me@linuxbox ~]$ mv "two words.txt" two_words.txt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
[me@linuxbox ~]$ echo this is a test this is a test [me@linuxbox ~]$ echo "this is a test" this is a test (calvagrant@precise64:~$ echo $(cal) September 2020 Su Mo Tu We Th Fr Sa 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 vagrant@precise64:~$ echo "$(cal)" September 2020 Su Mo Tu We Th Fr Sa 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
- Single Quotes: 单引号 中的内容 扩展 全部 失效。
- Escaping Characters: \
| escape sequence | meaning |
|---|---|
| \a | Bell |
| \b | Backspace |
| \n | Newline |
| \r | Carriage return |
| \t | Tab |
- Signals: Signals are one of several ways that the operating system communicates with programs
kill: The kill command doesn’t exactly “kill” processes: rather it sends them signals kill [-signal] PID…
keyboard signal Ctrl-c INT Ctrl-z TSTP Number Name Meaning 1 HUP Hangup. This is a vestige of the good old days when terminals were attached to remote computers with phone lines and modems. The signal is used to indicate to programs that the controlling terminal has “hung up.” The effect of this signal can be demonstrated by closing a terminal session. The foreground program running on the terminal will be sent the signal and will terminate. 2 INT Interrupt. This performs the same function as a Ctrl-c sent from the terminal. It will usually terminate a program. 9 KILL Kill. This signal is special. Whereas programs may choose to handle signals sent to them in different ways, including ignoring them all together, the KILL signal is never actually sent to the target program. Rather, the kernel immediately terminates the process. When a process is terminated in this manner, it is given no opportunity to “clean up” after itself or save its work. For this reason, the KILL signal should be used only as a last resort when other termination signals fail. 15 TERM Terminate. This is the default signal sent by the kill command. If a program is still “alive” enough to receive signals, it will terminate. 18 CONT Continue. This will restore a process after a STOP or TSTP signal. This signal is sent by the bg and fg commands. 19 STOP Stop. This signal causes a process to pause without terminating. Like the KILL signal, it is not sent to the target process, and thus it cannot be ignored. 20 TSTP Terminal stop. This is the signal sent by the terminal when Ctrl-z is pressed. Unlike the STOP signal, the TSTP signal is received by the program, but the program may choose to ignore it. 3 QUIT Quit 11 SEGV Segmentation violation. This signal is sent if a program makes illegal use of memory, that is, if it tried to write somewhere it was not allowed to write. 28 WINCH Window change. This is the signal sent by the system when a window changes size. Some programs , such as top and less will respond to this signal by redrawing themselves to fit the new window dimensions. example, kill -number -Name 也即是说 kill 可以接受 number 或者 显示的名称 1 2
[me@linuxbox ~]$ kill -1 13546 [me@linuxbox ~]$ kill -SIGINT 13608
Configuration and the Environment
Environment: shell维护一个shell的 session信息 称为 环境; 两种形式: environment variables + shell variables。但是无法区分 两种类型的变量。
- printenv: 用来展现所有的 变量
- set: 不带参数 展现所有变量以及 shell函数
- alias: 展现所有 alias 相关的
- export: 设定环境变量,在之后的程序可见
- Environment 中的变量是 如何定义的:
- A login shell session: A login shell session is one in which we are prompted for our username and password. This happens when we start a virtual console session, for example.
- A non-login shell session: A non-login shell session typically occurs when we launch a terminal session in the GUI.
Login Shell Sessions 读取配置文件 顺序:
File Contents /etc/profile A global configuration script that applies to all users. ~/.bash_profile A user’s personal startup file. This can be used to extend or override settings in the global configuration script. ~/.bash_login If ~/.bash_profile is not found, bash attempts to read this script. ~/.profile If neither ~/.bash_profile nor ~/.bash_login is found, bash attempts to read this file. This is the default in Debian-based distributions, such as Ubuntu. Non-Login Shell Sessions 读取配置文件: non-login shells inherit the environ- ment from their parent process, usually a login shell. Non-login 会 继承 Login shell 的环境
File Contents /etc/bash.bashrc A global configuration script that applies to all users ~/.bashrc A user’s personal startup file. It can be used to extend or override settings in the global configuration script.
- 修改env的常见规则: 在 .bash_profile 中修改PATH 或者定义其他的环境变量。 .bashrc 所有的其他的一切
- source ~/.bashrc 强制加载 配置文件, (一般在更改 .bashrc之后只有重启 terminal 才会生效,如果想立即生效,可以使用source ~/.bashrc 或者 . ~/.bashrc)
- 命令查找: ls 命令的 定义在哪里, 又是如何找到的呢?
- shell 从 PATH 变量中 包含的 Path 中 顺序查找
1 2 3 4 5
PATH=$PATH:$HOME/bin export PATH 简单的将 $HOME/bin 添加到 PATH 中 (注意 $HOME 会在此处求值) export PATH 让 shell之后的process 中的PATH都改变
- Customizing the Prompt: 由 PS1变量控制 PS1 (short for “prompt string 1”).
Tools:
网络:
- ping, traceroute, ip(ifconfig), netstat, ftp, wget, ssh, scp, sftp
查找文件
- locate : 非常简单有效,只能使用 filename 用来查找。 locate 足够高效 因为 其从 updatedb command 更新的数据库中来进行查找,updatedb 经常 放在cron job 来执行(需要确认下,因为没有找到 相关的配置文件)
find 寻找文件 则显得 复杂 而详尽。可以根据给定的 目录 以及 各个限定 来查找文件。 可选参数与 含义
参数 可选值 -type b: Block special device file; c: Character special device file; d: Directory; f: regular file; l Symbolic link -size c Bytes; w: 2-byte words; k: kilobytes; M: megabytes; G: Gigabytes; -cmin n Match files or directories whose content or attributes were last modified exactly n minutes ago. To specify less than n minutes ago, use -n, and to specify more than n minutes ago, use +n. -cnewer file Match files or directories whose contents or attributes were last modified more recently than those of file. -ctime n Match files or directories whose contents or attributes were last modified n*24 hours ago. -empty Match empty files and directories. -iname pattern Like the -name test but case-insensitive. -inum n Match files with inode number n. This is helpful for finding all the hard links to a particular inode. -mmin n Match files or directories whose contents were last modified n minutes ago. -mtime n Match files or directories whose contents were last modified n*24 hours ago. -name pattern Match files and directories with the specified wildcard pattern. -newer file Match files and directories whose contents were modified more recently than the specified file. This is useful when writing shell scripts that perform file backups. Each time you make a backup, update a file (such as a log) and then use find to determine which files have changed since the last update -samefile name Similar to the -inum test. Match files that share the same inode number as file name -user name Match files or directories belonging to user name. The user may be expressed by a username or by a numeric user ID.
for example:
1
find ~ -type f -name "*.JPG" -size +1M | wc -l
注意 其中的 -name 参数需要添加 “” 来防止 pathname expansion, size: 则使用 +1M 表示大于 1M 的文件
find logical Operators: find 则可以更复杂的 使用 -and -or -not () 等来进行 logic 之间的 与或 操作 来设定更复杂的 test 关系
1
( expression 1 ) -or ( expression 2 )
Predefined Actions:
Action Meaning -delete delete match file -ls ls -dils match file -print output full pathname of match file -quit Quit once a match has been made User-Defined Actions: -exec rm ‘{}’ ‘;’: {} 代表 match file 的pathname。 这里面 存在的问题是: -exec 中的命令会被 实例化 多次,在每次match file的时候 就会实例化一次。可以简单的 实例化多次 修改为 实例化一次 。 即:
1 2 3 4 5 6 7 8
find ~ -type f -name 'foo*' -exec ls -l '{}' ';' -rwxr-xr-x 1 me me 224 2007-10-29 18:44 /home/me/bin/foo -rw-r--r-- 1 me me 0 2016-09-19 12:53 /home/me/foo.txt // 修改后 find ~ -type f -name 'foo*' -exec ls -l '{}' + -rwxr-xr-x 1 me me 224 2007-10-29 18:44 /home/me/bin/foo -rw-r--r-- 1 me me 0 2016-09-19 12:53 /home/me/foo.txt
xargs: 用于将 接受的input 的信息 作为参数 传递给 command. xargs存在的原因在于: 一些 命令 接受 命令行参数+标准输入,但是其他一些命令 则 只接受命令行 输入,所以需要 xargs 将标准输入 转换为 命令行参数 Some commands such as grep and awk can take input either as command-line arguments or from the standard input. However, others such as cp and echo can only take input as arguments, which is why xargs is necessary. [name] xargs 中存在一些 问题,主要是 关于 filename 中的空格,等分隔符号 对整个 shell的参数接收 都有影响。 所以 接受filename 的时候 –null 参数 将 是xargs 不被 ‘ ’分隔( 使用 空字符串 作为分隔), -d ‘
Archiving and Backup:
compressor command: gzip bzip2, gzip options
Option Long Option Desc -c –stdout Write output to standard output and keep the original files. -d –decompress Decompress This causes gzip act like gunzip -f –force force compress event if a compressed file already exists -l –list 应用 已压缩文件 展示 压缩信息 -r –recursive 递归压缩目录下的文件(目录下的文件各自压缩为 各自的压缩文件,所以 依然需要archive 程序) -v –verbose Display verbose messages while compressing. -number Set amount of compression. number is an integer in the range of 1 (fastest, least compression) to 9 (slowest, most compression). The values 1 and 9 may also be expressed as –fast and –best, respectively. The default value is 6. bzip2 同gzip 一样 为压缩程序,其中的参数 都大概相同,除了-r -number 外。 bunzip2 bzcat 用于解压缩。 bzip2recover 可以恢复受损的 压缩文件
archive command: tar zip: Archiving is the process of gathering up many files and bundling them together into a single large file.
Mode Meaning c Create an archive from a list of files and/or directories. x Extract an archive. r Append specified pathnames to the end of an archive t List the content of an archive 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
[me@linuxbox ~]$ gzip foo.txt [me@linuxbox ~]$ ls -l foo.* -rw-r--r-- 1 me me 3230 2018-10-14 07:15 foo.txt.gz [me@linuxbox ~]$ gzip -d foo.txt.gz [me@linuxbox ~]$ gunzip foo.txt [me@linuxbox ~]$ ls -l foo.* -rw-r--r-- 1 me me 15738 2018-10-14 07:15 foo.txt [me@linuxbox ~]$ bzip2 foo.txt [me@linuxbox ~]$ ls -l foo.txt.bz2 -rw-r--r-- 1 me me 2792 2018-10-17 13:51 foo.txt.bz2 [me@linuxbox ~]$ bunzip2 foo.txt.bz2
tar: 只能以 相对路径 archive 文件。unarchive 的时候 在 当前路径下 以相对路径 恢复文件。example
1 2 3 4 5 6
cd foo tar xf ../playground2.tar ls home playground tar cf playground2.tar ~/playground
–wildcards 可以用来过滤掉 特定的 match 文件 \n find 经常用来 与 tar 配合进行 批量 archive
1
2
3
4
5
```shell
find playground -name 'file-A' -exec tar rf playground.tar '{}' '+'
find playground -name 'file-A' | tar cf - --files-from=- | gzip > playground.tgz
```
第二条命令比较 特殊,在其中 tar cf - –files-from=- 中, - 代表 标准 标准输入或者输出 tar 可以通过添加 z j 参数,直接 使用gzip bzip2 进行压缩, z: gzip .tgz, j: bzip2 .tbz
1
2
3
```shell
find playground -name 'file-A' | tar czf playground.tgz -T -
```
通过网络进行 文件备份:
1
ssh remote-sys 'tar cf - Documents' | tar xf -
zip, unzip: 的命令 比较详细,所以只列出简短 的示例:
1
2
3
zip -r playground.zip playground // -r 是必须,这样才能 得到 playground 下的所有 archive
unzip ../playground.zip // 不同与 tar, zip 使用unzip 来进行 unarchive
unzip -l ../playground.zip
- sync command: rsync rsync options source destination where source and destination are one of the following:
- A local file or directory
- A remote file or directory in the form of [user@]host:path
- A remote rsync server specified with a URI of rsync://[user@]host[:port]/path
注意: source destination 其中之一 必须 为 本地的文件, 远程 到 远程的 copy 是不被允许的。 示例:
1
2
3
4
5
rsync -av source destination // -a 代表 archive mode, v verbose output
rsync -av source/ destination
// 两种方式不同的地方在于 后一种 只拷贝 source 中的内容到 destination, 而 第一种 则将source 目录也 拷贝到 destination 中.
rsync -av --delete source/ destination // delete 参数 为 完全拷贝, source 中删除掉的file 将在 destination 中删除掉。
- Using rsync Over a Network: 的两种方式
- source 安装了 rsync 的机器 以及 destination 安装了 远程shell 程序, 如: ssh
- destination 安装了 rsync server, rsync 可以配置为 daemon 模式 等待 sync 请求
1
2
3
sudo rsync -av --delete --rsh=ssh /etc /home /usr/local remote-sys:/backup
// 这里面 --rsh 指定为 ssh, 使 rsync 能够 使用ssh 来进行同步操作
rsync -av –delete rsync://archive.linux.duke.edu/ fedora/linux/development/rawhide/Everything/x86_64/os/ fedora-devel
Text Processing:
cat, sort, uniq, cut, paste, join, comm, diff, patch, tr, sed, aspell
- grep :
cat:
1 2 3
cat > foo.txt // ctrl-d结束输入 cat -A foo.txt // 其中 ^I 代表 tab, $ 代表 line末尾, 所以可以用此来 区分 tab 与 space cat -nA foo.txt // n 显式 line number
sort : 对输入进行排序, 是一个比较复杂,有用的命令:下面是详细参数
Option Long Option meaning -b –ignore-leading-blanks 使忽略掉 行前的 空格,使用第一个非空格排序 -f –ignore-case -n –numeric-sort 将字符串当做number 来进行比较 -r –reverse reverse order 排序 -k –key=field1[,field2] 使用 field1..field2 作为排序的key, field1 不存在则为1, field2 不存在则 从field1直至末尾, field1 都可以是如此形式 f[.c][opts] .c 为内部的offset -m –merge 将每个参数作为预排序文件的名称。 将多个文件合并为单个排序结果,而不执行任何其他排序。 -o –output=file 输出到 file 而非 标准输出 -t –field-separator=char 使用 char 作为分隔符,默认为 space 或者tab –debug 将用作sort 的key 进行标记 下面是几个示例
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 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
[me@linuxbox ~]$ du -s /usr/share/* | head 252 /usr/share/aclocal 96 /usr/share/acpi-support 8 /usr/share/adduser 196 /usr/share/alacarte 344 /usr/share/alsa 8 /usr/share/alsa-base 12488 /usr/share/anthy 8 /usr/share/apmd // 下面对结果进行排序 其中 -nr 将string作为number 处理并 翻转排序, 这里面之所有管用,是因为 第一列 为 数字, 即 默认按照第一列进行排序 [me@linuxbox ~]$ du -s /usr/share/* | sort -nr | head 509940 /usr/share/locale-langpack 242660 /usr/share/doc 197560 /usr/share/fonts 179144 /usr/share/gnome 146764 /usr/share/myspell 144304 /usr/share/gimp 135880 /usr/share/dict 76508 /usr/share/icons 68072 /usr/share/apps 62844 /usr/share/foomatic // 如果是这样的又如何排序? [shaohua.li@10-11-112-3 ~]$ ls -l /usr/bin/ | head total 58404 -rwxr-xr-x 1 root root 33408 Nov 10 2015 [ -rwxr-xr-x 1 root root 106792 Nov 10 2015 a2p -rwxr-xr-x. 1 root root 14984 Aug 18 2010 acpi_listen -rwxr-xr-x. 1 root root 23488 Nov 11 2010 addftinfo -rwxr-xr-x 1 root root 24904 Jul 23 2015 addr2line -rwxr-xr-x. 1 root root 1786 Feb 21 2013 apropos -rwxr-xr-x 1 root root 56624 Jul 23 2015 ar -rwxr-xr-x 1 root root 328392 Jul 23 2015 as -rwxr-xr-x. 1 root root 10400 Sep 23 2011 attr // -k 5 使用 第 5 field 作为key 用作 排序使用 [shaohua.li@10-11-112-3 ~]$ ls -l /usr/bin/ | sort -nr -k 5 | head -rwxr-xr-x 1 root root 3214440 Dec 12 2016 mysql -rwxr-xr-x 1 root root 3051080 Dec 12 2016 mysqlbinlog -rwxr-xr-x 1 root root 2998400 Dec 12 2016 mysqldump -rwxr-xr-x 1 root root 2948832 Dec 12 2016 mysqlslap -rwxr-xr-x 1 root root 2936680 Dec 12 2016 mysqladmin -rwxr-xr-x 1 root root 2935688 Dec 12 2016 mysqlcheck -rwxr-xr-x 1 root root 2933128 Dec 12 2016 mysqlimport -rwxr-xr-x 1 root root 2931712 Dec 12 2016 mysqlshow -rwxr-xr-x 1 root root 2814328 Dec 12 2016 my_print_defaults -rwxr-xr-x 1 root root 2811544 Dec 12 2016 mysql_waitpid // 下面是 比较复杂的示例 root@precise64:~/shell_test# cat distros.txt Fedora 5 03/20/2006 Fedora 6 10/24/2006 Fedora 7 05/31/2007 Fedora 8 11/08/2007 Fedora 9 05/13/2008 Fedora 10 11/25/2008 SUSE 10.1 05/11/2006 SUSE 10.2 12/07/2006 SUSE 10.3 10/04/2007 SUSE 11.0 06/19/2008 Ubuntu 6.06 06/01/2006 Ubuntu 6.10 10/26/2006 Ubuntu 7.04 04/19/2007 Ubuntu 7.10 10/18/2007 Ubuntu 8.04 04/24/2008 Ubuntu 8.10 10/30/2008 // 如何对 distros 按照其 发布的版本 以及 发布时间 进行排序呢? // 单纯的 按照 发布版本排序 root@precise64:~/shell_test# sort distros.txt -nrk 2 SUSE 11.0 06/19/2008 SUSE 10.3 10/04/2007 SUSE 10.2 12/07/2006 SUSE 10.1 05/11/2006 Fedora 10 11/25/2008 Fedora 9 05/13/2008 Ubuntu 8.10 10/30/2008 Ubuntu 8.04 04/24/2008 Fedora 8 11/08/2007 Ubuntu 7.10 10/18/2007 Ubuntu 7.04 04/19/2007 Fedora 7 05/31/2007 Ubuntu 6.10 10/26/2006 Ubuntu 6.06 06/01/2006 Fedora 6 10/24/2006 Fedora 5 03/20/2006 // 综合排序, 使用多个key, 版本,以及版本号 进行综合排序 root@precise64:~/shell_test# sort --key=1,1 --key=2n distros.txt Fedora 5 03/20/2006 Fedora 6 10/24/2006 Fedora 7 05/31/2007 Fedora 8 11/08/2007 Fedora 9 05/13/2008 Fedora 10 11/25/2008 SUSE 10.1 05/11/2006 SUSE 10.2 12/07/2006 SUSE 10.3 10/04/2007 SUSE 11.0 06/19/2008 Ubuntu 6.06 06/01/2006 Ubuntu 6.10 10/26/2006 Ubuntu 7.04 04/19/2007 Ubuntu 7.10 10/18/2007 Ubuntu 8.04 04/24/2008 Ubuntu 8.10 10/30/2008 // k 可以为 f[.c][opts] 可以指定 field 中的 c pos 用来比较 root@precise64:~/shell_test# sort -k 3.7nbr -k 3.1nbr -k 3.4nbr distros.txt Fedora 10 11/25/2008 Ubuntu 8.10 10/30/2008 SUSE 11.0 06/19/2008 Fedora 9 05/13/2008 Ubuntu 8.04 04/24/2008 Fedora 8 11/08/2007 Ubuntu 7.10 10/18/2007 SUSE 10.3 10/04/2007 Fedora 7 05/31/2007 Ubuntu 7.04 04/19/2007 SUSE 10.2 12/07/2006 Ubuntu 6.10 10/26/2006 Fedora 6 10/24/2006 Ubuntu 6.06 06/01/2006 SUSE 10.1 05/11/2006 Fedora 5 03/20/2006 // --debug 选项 是比较有意思的,用来在 不知道 key 以及sort情况时候,用来展现 其内部sort key 的方式 root@precise64:~/shell_test# cat /etc/passwd | sort -t ':' -k 7 --debug | head sort: using `en_US' sorting rules root:x:0:0:root:/root:/bin/bash _________ _______________________________ vagrant:x:1000:1000:vagrant,,,:/home/vagrant:/bin/bash _________ ______________________________________________________ messagebus:x:102:105::/var/run/dbus:/bin/false __________ ______________________________________________ mysql:x:106:111:MySQL Server,,,:/nonexistent:/bin/false
uniq: 去除 重复的 条目, 比较有意思的是 需要在sort之后 使用,也就是说 uniq只能去除掉 相邻的 重复的条目
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
[me@linuxbox ~]$ cat > foo.txt a b c a b c [me@linuxbox ~]$ uniq foo.txt a b c a b c [me@linuxbox ~]$ sort foo.txt | uniq a b c
cut: 用于 使用 -d, –delimiter=DELIM 默认为tab 分隔line, 然后提取 field -f list, characters 等
1 2 3 4 5 6 7 8 9 10 11
root@precise64:~/shell_test# cat /etc/passwd | cut -d ':' -f 1 | head root daemon bin sys sync games man lp mail news
comm: 用于比较 两个文本的变化差异: comm file1 file2 其结果 第一列 显式 file1 独有的,第二列 显示 file2 独有的, 第三列 显示 file1 file2 共同的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
root@precise64:~/shell_test# cat file1.text a b c d root@precise64:~/shell_test# cat file2.text b c d e // 注意 其展现形式, 第一列only file1 have 第二列 only file2 have 第三列 comm root@precise64:~/shell_test# comm file1.text file2.text a b c d e
- https://toroid.org/unix-pipe-implementation
diff: diff file1.txt file2.txt; diff 展现的格式 都为 更改 file1.txt 转变到 file2.txt 的操作序列,即是 字符串 之间最小编辑记录 在文件中的应用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
root@precise64:~/shell_test# cat file1.text a b c d root@precise64:~/shell_test# cat file2.text b c d e root@precise64:~/shell_test# diff file1.text file2.text 1d0 < a 4a4 > e
Change meaning r1ar2 将 file2 中的 r2行 追加到 file1 中的 r1 行中 r1cr2 将 file1 中 r1 行 替换为 file2中的 r2 行 r1dr2 将 file1中的r1行删除掉,下一行将出现在 file2中的 r2 行 此格式为默认格式,但是因为不够直观,所以这种格式并不常用。 上下文格式:diff -c file1.txt file2.txt
1 2 3 4 5 6 7 8 9 10 11 12 13 14
root@precise64:~/shell_test# diff -c file1.text file2.text *** file1.text 2020-09-24 08:02:08.202406914 +0000 // ** 代表 file1.txt,其后是 时间戳 --- file2.text 2020-09-24 08:02:15.854515682 +0000 // -- 代表 file2.txt 其后是 时间戳 *************** *** 1,4 **** // ** 代表 file1.txt - a b c d --- 1,4 ---- // -- 代表 file2.txt b c d + e
Indicator Meaning blank 此行 两个文件没有差别 - 需要删除该行(只会出现在 file1中,因为目的是 将file1 转向 file2) + 添加该行 (只会出现在file2中,代表 需要将该行添加到 file1中) ! 两个文件中都会出现,代表 file1中的该行 需要被 file2中的 对应行 替换 统一格式: diff -u file1.txt file2.txt
1 2 3 4 5 6 7 8 9
root@precise64:~/shell_test# diff -u file1.text file2.text --- file1.text 2020-09-24 08:02:08.202406914 +0000 +++ file2.text 2020-09-25 04:41:15.154310271 +0000 @@ -1,4 +1,4 @@ -a b c d +e
Character Meaning blank no change - 从file1 文件中删除该行 + 从file1 文件中添加该行 也就是说 统一格式 中,将 !替换操作去除了,通过 - + 来实现了 替换操作
- patch: 用来将diff 出的结果 apply。 即是: diff -Naur old_file new_file > diff_file; patch < diff_file; 之后 old_file 会转变为 same as new_file
tr: 基于字符的替换工具, tr 只能基于 单个字符进行替换操作, 无法进行 多个字符串的匹配替换操作. -s squeeze delete 将连续的字符进行删除操作 for example:
1 2 3
echo "lowercase letters" | tr a-z A-Z // LOWERCASE LETTERS echo "aaabbbccc" | tr -s ab // abccc
- sed:
Text format: nl, fold, fmt, pr, printf, groff
shell 语法
The #! character sequence is, in fact, a special construct called a shebang. The shebang is used to tell the kernel the name of the interpreter that should be used to execute the script that follows. Every shell script should include this as its first line
Good Locations for Scripts The ~/bin directory is a good place to put scripts intended for personal use. If we write a script that everyone on a system is allowed to use, the traditional location is /usr/ local/bin. Scripts intended for use by the system administrator are often located in / usr/local/sbin. In most cases, locally supplied software, whether scripts or com- piled programs, should be placed in the /usr/local hierarchy and not in /bin or / usr/bin. These directories are specified by the Linux Filesystem Hierarchy Standard to contain only files supplied and maintained by the Linux distributor.
Variables and Constants
- shell 中的变量 是 动态的,不需要预先声明 与类型指定(因为没有类型,可能都为字符串),对于 使用 未定义 未赋值 的变量 其 数值 为 空。 所以我们需要 注意自己的拼写错误,因为 shell可能会将其视为 新变量。
- 常量: 规范 使用 全大写 命名 常量,以区分于 普通变量。 也可以使用 declare -r TITLE=”Page Title” 来进行声明
- 赋值: variable=value shell 并不区分 value的类型, value 全部被视为 string, 注意= 左右没有空格
- 变量数值引用 需要注意, 因为语法原因 可能 需要使用 {} 来避免 变量名与表达式 的歧义
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
a=z # a 赋值为 string z
b="a string"
c="a string and $b" # c
d="$(ls -l foo.txt)" # value 为子命令结果
e=$((5 * 7)) # 数值计算展开
a=5 b="string" # 多个变量可以 同时声明
filename="myfile"
touch $filename
mv "$filename" "$filename1" # 这里面的本意是 更改myfile 文件为 myfile1,但是因为并没有 区分 $filename1 是变量还是表达式, 所以这里需要 使用新的形势 来进行区分
mv: missing destination file operand after `myfile'
Try `mv --help' for more information.
mv "$filename" "${filename}1" # 使用 {} 来解决歧义
here doc: 优势在于在 Here doc内部的 “ ‘ 都会失去含义, 可以方便的构建json
1
2
3
4
5
6
7
8
```shell
command << token
text
token
# command is the name of command that accepts standard input and token is a string used to indicate the end of the embedded text
```
function define:
1
2
3
4
5
6
7
8
9
10
function name {
commands
return
}
name() {
commands
return
}
- local var: 局部变量, local foo=
- function 之间的数据传递: 有三种 答案在这里: https://stackoverflow.com/questions/8742783/returning-value-from-called-function-in-a-shell-script
其中使用echo 方式传递 返回值 的方式 类似于 local name=$(cat xxx grep) 等, 即: 使用 Process Substitution 来分离出一个process 执行 shell 代码, 通过 stdin stdout stderr 等来实现 process的处理结果
Flow Control:
- if
1
2
3
4
5
6
7
if commands; then
commands
[elif commands; then
commands...]
[else
commands]
fi
- exit status: 一般为 为一个 0-255 的数值, 0 代表 success, 其他值代表不同的错误。所以0 代表true,false 代表1, 不同于其他语言中的惯例。$? 代表 上个命令执行的返回结果
1
2
3
4
5
6
7
8
root@precise64:~/shell_test# ls -d /usr/bin/
/usr/bin/
root@precise64:~/shell_test# echo $?
0
root@precise64:~/shell_test# ls -d /bin/usr
ls: cannot access /bin/usr: No such file or directory
root@precise64:~/shell_test# echo $?
2
test: 配合if 使用,返回condition 结果: 两种形式. 成功返回0, 失败 返回1
1 2 3
test expression [ expression ]
相关的测试expression
file Expression
Expression Is True? file1 -ef file2 file1 inode eq file2 inode true file1 -nt file2 file1 is newer than file2 file1 -ot file2 file1 is older than file2 -b file file exist and is a block-special file -c file file exist and is a char-special file -d file file exists and is a dir -e file file exists -f file file exists and a regular file -g file file exists and is set-group-id -G file file exists and is owner by the effective group ID -k file file exists and has its ‘sticky bit’ sit -L file file exists and is a sym link -p file file exists and a named pipe -r file file exists and can readable -s file file exists and has a length greater than zero -S file file exists and a socket -w file file exists and writable -x fiel file exists and executeable
1 2 3 4 5 6 7 8 9 10 11
if [ -e "$FILE" ]; then if [ -f "$FILE" ]; then echo "$FILE is a regular file." fi if [ -d "$FILE" ]; then echo "$FILE is a directory." fi if [ -r "$FILE" ]; then echo "$FILE is readable." fi fi
string expression
Expression Meaning string string is not null -n string string len is not zero -z string string len is zero str1 == str2 equal str1 != str2 not equal str1 > str2 str1 sorts after str2 str1 < str2 str1 sort before str2 1 2 3 4 5 6 7 8 9 10 11 12 13 14
ANSWER=maybe if [ -z "$ANSWER" ]; then echo "There is no answer." >&2 exit 1 fi if [ "$ANSWER" = "yes" ]; then echo "The answer is YES." elif [ "$ANSWER" = "no" ]; then echo "The answer is NO." elif [ "$ANSWER" = "maybe" ]; then echo "The answer is MAYBE." else echo "The answer is UNKNOWN." fi
这里面 需要注意: the > and < expression operators must be quoted (or escaped with a backslash) when used with test. If they are not, they will be interpreted by the shell as redirection operators
Integer Expressions
Expression Meaning int1 -eq int2 equal int1 -ne int2 not equal int1 -le int2 int1 <= int2 int1 -lt int2 int1 < int2 int1 -ge int2 int1 >= int2 int1 -gt int2 int1 > int2 - [[ expression ]] : 类似于 [ expression ], 区别在于: 增加了 string1 =~ regex 测试方法 2. == 支持 pathname expansion 检测
- (( )): Designed for Integers, 用于测试 数学计算, 如果数值 为非0 则是true, 0则为false。在(()) 中变量可以直接 使用,不用带 $, 例如, 在其中可以使用所有的数学表达式,比如 >, <, >=, <=, ==, %, /, * etc
1
2
3
4
INT=5
if ((INT == 0)); then
echo "INT is zero"
fi
Combining Expressions:
Operation test [[]] and (()) AND -a && OR -o NOT ! ! for example:
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
#!/bin/bash MIN_VAL=1 MAX_VAL=100 INT=50 if [[ "$INT" =~ ^-?[0-9]+$ ]]; then if [[ "$INT" -ge "$MIN_VAL" && "$INT" -le "$MAX_VAL" ]]; then echo "$INT is within $MIN_VAL to $MAX_VAL." else echo "$INT is out of range." fi else echo "INT is not an integer." >&2 exit 1 fi # 等价的另一种方式 if [ "$INT" -ge "$MIN_VAL" -a "$INT" -le "$MAX_VAL" ]; then echo "$INT is within $MIN_VAL to $MAX_VAL." else echo "$INT is out of range." fi
read: read 用于 从标准输入中 读取数值。
| Options | Desc |
|---|---|
| -a array | 将输入赋值(转化)给 数组 |
| -e | 使用 Readline 模式 处理输入 |
| -i string | 默认数值,在玩家仅仅按 enter的时候 有用 |
| -p prompt | 输入的 提示信息 |
| -r | Raw mode. Do not interpret backslash characters as escapes. |
| -s | slient mode, 用于密码输入 |
| -t seconds | Timeout after seconds |
| -u fd | 使用file 作为输入,而不是标准输入 |
- read:将 标准输入 转到 变量 的使用格式: read [-options] [variable…]
- read 存在默认变量 REPLY,即当没有 variable 传递的时候
- for example
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#!/bin/bash
echo -n "please enter an integer -> "
read int
if [[ "$int" =~ ^-?[0-9]+$ ]]; then
if (( int == 0 )); then
echo "int is zero"
else
if (( int < 0)); then
echo "$int is negative"
else
echo "$int is positive"
fi
fi
fi
# read 多个var 测试, 与ruby array 复制差不多,
# 即是:当多个 参数数目 > 变量数目 时 剩余的变量为空值,当 参数数目 < 变量数目时 最后后一个变量 存储多个数值
#!/bin/bash
# read-multiple: read multiple values from keyboard
echo -n "Enter one or more values > "
read var1 var2 var3 var4 var5
echo "var1 = '$var1'"
echo "var2 = '$var2'"
echo "var3 = '$var3'"
echo "var4 = '$var4'"
echo "var5 = '$var5'"
vagrant@precise64:/vagrant_data/shell_test$ ./read-multiple.sh
Enter one or more values > 1 2 3 4 4 45 5
var1 = '1'
var2 = '2'
var3 = '3'
var4 = '4'
var5 = '4 45 5'
vagrant@precise64:/vagrant_data/shell_test$ ./read-multiple.sh
Enter one or more values > 1
var1 = '1'
var2 = ''
var3 = ''
var4 = ''
var5 = ''
# read 不传递 var 时候,默认使用变量 REPLY
#!/bin/bash
# read-single: read multiple values into default variable
echo -n "Enter one or more values > "
read
echo "REPLY = '$REPLY'"
vagrant@precise64:/vagrant_data/shell_test$ ./read-single.sh
Enter one or more values > 1
REPLY = '1'
- IFS (Internal Field Separator) : 用来控制 read 分隔line 的分隔符, 默认的IFS 包含 space, tab, newline
使用read的 这种方式, 可以很简单的 做 字符串的 split
1 2
IFS=":" read user pw uid gid name home shell <<< "root:x:0:0:root:/root:/bin/bash" echo "string: ${user}, pw: ${pw}, uid: ${uid}, shell: ${shell}"
Flow Control: Looping with while/until
while: shell 中 同样存在 continue break 可供使用,以便提前 循环、或者 终止循环
1 2 3 4 5 6 7 8 9 10 11
while commands; do commands done count=1 while [[ "$count" -le 5 ]];do echo "$count" count=$((count + 1)) done echo "Finished."
until: 与while 同样的基本结构,不过测试条件相反
1 2 3 4 5 6 7
#!/bin/bash # until-count: display a series of numbers count=1 until [[ "$count" -gt 5 ]]; do echo "$count" count=$((count + 1)) done echo "Finished."
读取文件的循环示例:
1 2 3 4 5 6 7 8
#!/bin/bash # while-read: read lines from a file while read distro version release; do printf "Distro: %s\tVersion: %s\tReleased: %s\n" \ "$distro" \ "$version" \ "$release" done < distros.txt
shell 的测试: 1) 除了 print 大法好(在这里是echo 之外) 2) #!/bin/bash -x 这样在脚本运行期间,将会 展示详细信息, 可以 使用 set +x 关闭 tracing set -x开启 tracing
case: 使用 pattern 进行匹配,) 结束 匹配。 还可以参考链接 http://tiswww.case.edu/php/chet/bash/bashref.html#SEC21 http://tldp.org/LDP/abs/html/testbranch.html 因为这里面介绍的十分简单
Pattern Desc a) Match if word equal ‘a’ [[:aplpha:]]) Match if word is a single alphabetic char ???) Match if word is exactly three char long *.txt) Match if word ends with the char “.txt” *) Matches anyy value of word 1 2 3
case word in [pattern [| pattern]...) commands ;;]... esac
for example
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
#!/bin/bash -x read -p "Enter selection [0-3] > " case "$REPLY" in 0) echo "Program terminated." exit ;; 1) echo "Hostname: $HOSTNAME" uptime ;; 2) df -h ;; 3) if [[ "$(id -u)" -eq 0 ]]; then echo "Home Space Utilization (All Users)" du -sh /home/* else echo "Home Space Utilization ($USER)" du -sh "$HOME" fi ;; *) echo "Invalid entry" >&2 exit 1 ;; esac
for loop:
传统形式
1 2 3
for variable [in words]; do commands done
c语言形式: 只支持 在对 数字 进行操作的时候
1 2 3 4 5 6 7 8 9
```shell for (( expression1; expression2; expression3 )); do commands done for (( i=0; i<5; i=i+1 )); do echo $i done ```example
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
[me@linuxbox ~]$ for i in A B C D; do echo $i; done A B C D for i in {A..D}; do echo $i; done A B C D [me@linuxbox ~]$ for i in distros*.txt; do echo "$i"; done distros-by-date.txt distros-dates.txt distros-key-names.txt distros-key-vernums.txt distros-names.txt distros.txt distros-vernums.txt distros-versions.txt # ./for_test.sh file for i; do echo "i in ---------- ${i} \n" done # 可以使用如此的方式,循环打印 command line 参数 root@precise64:/vagrant_data/shell_test# ./for_test.sh a b c d e f j i in ---------- a \n i in ---------- b \n i in ---------- c \n i in ---------- d \n i in ---------- e \n i in ---------- f \n i in ---------- j \n
Accessing the Command Line:
- shell 中 通过 $0-$9 来接受 command line 传递的参数。其中9 并不是 参数个数的上线,可以使用 更多的比如 $11, $100000 来使用 第 1000000 个参数。
- $# 标志 参数个数。其中 $0 总是为 shell本身
shift: shift可以将 将 $1后续的变量,转移到 $1上, 同时 $# 减少
1 2 3 4 5 6 7
#!/bin/bash # posit-param2: script to display all arguments count=1 while [[ $# -gt 0 ]]; do echo "Argument $count = $1" count=$((count + 1)) shift done
- 函数 传递参数的方式 同上,使用 $0, $1 etc
- 常量: PROGNAME当前shell运行的函数, FUNCNAME 为shell当前运行的shell函数
$* $@ “$*” “$@” : “$@” 在这里面是最为 重要的,因为保留了 原来参数传递的样式
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
// fun_test.sh file #!/bin/bash # posit-params3: script to demonstrate $* and $@ print_params () { echo "\$1 = $1" echo "\$2 = $2" echo "\$3 = $3" echo "\$4 = $4" } pass_params () { echo -e "\n" '$*'; print_params $* echo -e "\n" '$*'; print_params "$*" echo -e "\n" '$@'; print_params $@ echo -e "\n" '$@'; print_params "$@" } pass_params "word" "words with spaces" // ./fun_test.sh 测试 root@precise64:/vagrant_data/shell_test# ./fun_test.sh $* $1 = word $2 = words $3 = with $4 = spaces $* $1 = word words with spaces $2 = $3 = $4 = $@ $1 = word $2 = words $3 = with $4 = spaces $@ $1 = word $2 = words with spaces $3 = $4 =
Strings and Numbers
expression meaning ${para:-word} para 为空 express result 为 word ${para:=word} para 为空 express & para result 为 word (position 参数不能够如此赋值) ${pars:?word} pars 为空 则exit,word被输出到 stderr ${para:+word} para不为空,则 expres 为 word ${!prefix*} 或者 ${!prefix@} 返回 以 prefix 为前缀的 变量名称 ${#para} para length, 如果 para 为 @ 或者 * 则 展开为 command line params size ${para:offset} ${para:offset:length} 用于string 的片段截取,没有length时候,则直到末尾, para为 @时候, 则为 参数 从 offset开始 到结尾 ${para#pattern} ${para##pattern} 将字符串remove pattern match的部分,结果为 剩下的部分, #pattern remove 最短的 match 部分, ## 则remove 最长的match ${para%pattern} ${para%%pattern} 同上,但是 remove 片段从string 的末尾开始,而非开头开始 ${para/pattern/string} ${para//pattern/string} ${para/#pattern/string} ${para/%pattern/string} string 的查找替换操作,使用 string 替换 para中的 pattern matched,第一个只替换第一个, 第二个则全部替换, 第三个 则替换开头, 第四个只替换末尾 case conversion parameter
Format Result ${pars,,} 展开为 para 的 全部小写形式 ${para,} 展开式 para 首字母 小写 ${para^^} 展开为 para 的全部 大写形式 ${para^} 展开为 para 首字母 大写形式
数字操作: $((expression)) 基本形式
Operators
Operator Desc + - * * / ** % para = value para += value para -= value para *= value para /= value para %= value para ++ para – ++ para – para <= >= < > != && expre1?expre2:expre3
Array: bash version2 才得到支持,在原先的shell中 并不支持 array
Create a Array :
1 2 3 4
a[1]=foo echo ${a[1]} declare -a a
- Assigning Values to an Array: name[subscript]=value; name=(value1 value2 …)
Array Operations: 遍历数组
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
[me@linuxbox ~]$ animals=("a dog" "a cat" "a fish") [me@linuxbox ~]$ for i in ${animals[*]}; do echo $i; done a dog a cat a fish [me@linuxbox ~]$ for i in ${animals[@]}; do echo $i; done a dog a cat a fish [me@linuxbox ~]$ for i in "${animals[*]}"; do echo $i; done a dog a cat a fish [me@linuxbox ~]$ for i in "${animals[@]}"; do echo $i; done a dog a cat a fish # "${!array[*]}", "${!array[@]}" [me@linuxbox ~]$ foo=([2]=a [4]=b [6]=c) [me@linuxbox ~]$ for i in "${foo[@]}"; do echo $i; done a b c # 展示数组 有value的 indexs [me@linuxbox ~]$ for i in "${!foo[@]}"; do echo $i; done 2 4 6
Sorting an Array:
1 2 3 4 5 6
#!/bin/bash # array-sort: Sort an array a=(f e d c b a) echo "Original array: ${a[@]}" # 传统的数组排序方式,因为shell并不会构建复杂的 类型系统 来进行 数组函数排序 a_sorted=($(for i in "${a[@]}"; do echo $i; done | sort)) echo "Sorted array: ${a_sorted[@]}"
Deleting an Array: unset array; unset ‘array[index]’ array=xxxx 修改 array[0] 中的数值
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
[me@linuxbox ~]$ foo=(a b c d e f) [me@linuxbox ~]$ echo ${foo[@]} a b c d e f [me@linuxbox ~]$ unset foo [me@linuxbox ~]$ echo ${foo[@]} [me@linuxbox ~]$ [me@linuxbox ~]$ foo=(a b c d e f) [me@linuxbox ~]$ echo ${foo[@]} a b c d e f [me@linuxbox ~]$ unset 'foo[2]' [me@linuxbox ~]$ echo ${foo[@]} a b d e f [me@linuxbox ~]$ foo=(a b c d e f) [me@linuxbox ~]$ foo= [me@linuxbox ~]$ echo ${foo[@]} b c d e f [me@linuxbox ~]$ foo=(a b c d e f) [me@linuxbox ~]$ echo ${foo[@]} a b c d e f [me@linuxbox ~]$ foo=A [me@linuxbox ~]$ echo ${foo[@]} A b c d e f
Group Commands and Subshells:
- Group Command: { command1; command2; [command3; …] }
Subshells: ( command1; command2; [command3;…] ) group commands 可以将 其中的command 的结果 很方便的 合并到一个 数据流汇总,例如:
1 2 3 4 5 6 7 8
( ls -l; echo "Listing of foo.txt"; cat foo.txt) > output.txt { ls -l; echo "Listing of foo.txt"; cat foo.txt; } > output.txt #等同于: ls -l > output.txt echo "Listing of foo.txt" >> output.txt cat foo.txt >> output.txt
Process Substitution: 区别于 group commands , Process sub 运行在 子进程 中,而group command 则运行在当前进程中, 所以从效率上来说 group command 要快于 process substitution, 该技术使得 子进程 中的输出 到当前进程中 进行处理。通常 将 子进程中的数据流 输出到当前 进程使用 read 处理。
形式为: <(list), >(list)。 for example
1 2 3 4 5
#!/bin/bash # pro-sub: demo of process substitution while read attr links owner group size date time filename; do done < <(ls -l | tail -n +2)
Traps: 处理 信号。trap argument signal [signal…] 其中 argument 为string, 例如:
1 2 3 4
trap "echo 'I am ignoring you.'" SIGINT SIGTERM trap exit_on_signal_SIGINT SIGINT trap exit_on_signal_SIGTERM SIGTERM
Shell 使用中的一些问题:
IFS 的重要性, IFS 对于 shell处理非常重要, 比如 echo的使用,在如下场景中存在问题:
通过 tail -c offset file 来获取 文件最新追加数据, 并保存到var(变量) 中, 以供后续 处理,匹配。1 2 3
content=$(tail -c ${offset} ${file}) echo ${content} // 会导致 newline (\n) 丢失, 丢失,导致后面的 grep 可能失败, 不能够正常表现, 所以需要 使用 echo "${content}" 来实现 newline 的保留, (newline 并没有因为保存在变量中,而被丢弃,只是因为IFS 包含 newline 没有表现出来) , 相关参考在 https://www.baeldung.com/linux/variable-preserve-linebreaks?utm_source=pocket_mylist match=$(echo "${content}" | grep 'app error: exception:' | grep -E "unexpected token at 'null' params|undefined method \`split' for nil:NilClass" -v)
错误重定向: /home/shaohua.li/error_monitor.sh » /home/shaohua.li/crontab_shell/task.log 2»&1 错误,在bash中会产生错误, zsh 则没有问题。所以这里的写法 应该是 » xxxx 2>&1 2会追加到 1 所以应该控制 1 的打开方式,但是这是否会存在 1 为 write, 2 也只能为 write 不能为append? 这里面的思考方式,应该是 写程序, 关于fd 的方式 (透过现象看本质,即 同一个程序 使用同一个 fd,以及打开fd 两次, 导致的偏移量的区别)
- cd , cd ~, cd ~user_name
- options & arguments: command -options arguments, GNU project also support two dash command –options arguments,
- mkdir directory… When three periods follow an argument in the description of a com- mand (as above), it means that the argument can be repeated, thus the following com- mand:
- ls -a (list all files) -A (like -a not include . and ..) -l (long format) -h (long fomart display file size in k,m,g ) -S (sort by file size) -t (sort by modification time) -r (reverse order)
- Wildcards expand : t provides special characters to help us rapidly specify groups of filenames.:
- (any)
- 单个位置: ? (single char) [chars] (match any chars that is a member of this set), [!characters] Character Ranges [A-Z] [a-z] [0-9] 可嵌套:[[:lower:]123]