bash shell 提供了用户自定义函数功能,可以将 shell 脚本代码放入函数中封装起来。
函数是一个脚本代码块,你可以为其命名并在脚本中的任何位置重用它。每当需要在脚本中使用该代码块时,直接写函数名即可(这叫作调用函数)。
在 bash shell 脚本中创建函数的语法有两种:
function name {
commands
}
name() {
commands
}
function func1 {
echo "This is an example of a function"
}
count=1
while [ $count -le 5 ]
do
func1
count=$[ $count + 1 ]
done
echo "This is the end of the loop"
func1
echo "Now this is the end of the script"
bash shell 把函数视为一个小型脚本,运行结束时会返回一个退出状态码。有 3 种方法能为函数生成退出状态码:
在默认情况下,函数的退出状态码是函数中最后一个命令返回的退出状态码。函数执行结束后,可以使用标准变量$?来确定函数的退出状态码。
function dbl {
read -p "Enter a value: " value
echo "doubling the value"
return $[ $value * 2 ]
}
dbl
echo "The new value is $?"
result=$(dbl)
function dbl {
read -p "Enter a value: " value
echo $[ $value * 2 ]
}
result=$(dbl)
echo "The new value is $result"
func1 $value1 10
function addem {
if [ $# -eq 0 ] || [ $# -gt 2 ]
then
echo -1
elif [ $# -eq 1 ]
then
echo $[ $1 + $1 ]
else
echo $[ $1 + $2 ]
fi
}
echo -n "Adding 10 and 15: "
value=$(addem 10 15)
echo $value
echo -n "Let's try adding just one number: "
value=$(addem 10)
echo $value
echo -n "Now try adding no numbers: "
value=$(addem)
echo $value
echo -n "Finally, try adding three numbers: "
value=$(addem 10 15 20)
echo $value
function badfunc1 {
echo $[ $1 * $2 ]
}
if [ $# -eq 2 ]
then
value=$(badfunc1)
echo "The result is $value"
else
echo "Usage: badtest1 a b"
fi
$
$ ./badtest1
Usage: badtest1 a b
$ ./badtest1 10 15
./badtest1: * : syntax error: operand expected (error token is "*
")
The result is
function func7 {
echo $[ $1 * $2 ]
}
if [ $# -eq 2 ]
then
value=$(func7 $1 $2)
echo "The result is $value"
else
echo "Usage: badtest1 a b"
fi
local temp
local temp=$[ $value + 5 ]
function testit {
echo "The parameters are: $@"
thisarray=$1
echo "The received array is ${thisarray[*]}"
}
myarray=(1 2 3 4 5)
echo "The original array is: ${myarray[*]}"
testit $myarray
$
$ ./badtest3
The original array is: 1 2 3 4 5
The parameters are: 1
The received array is 1
function testit {
local newarray
newarray=(`echo "$@"`)
echo "The new array value is ${newarray[*]}"
local sum=0
for value in ${newarray[*]}
do
sum=$[ $sum + $value ]
done
echo $sum
}
myarray=(1 2 3 4 5)
echo "The original array is: ${myarray[*]}"
testit ${myarray[*]}
function arraydblr {
local origarray
local newarray
local elements
local i
origarray=($(echo "$@"))
newarray=($(echo "$@"))
elements=$[ $# - 1 ]
for (( i = 0; i <= $elements; i++ ))
{
newarray[$i]=$[ ${origarray[$i]} * 2 ]
}
echo ${newarray[*]}
}
myarray=(1 2 3 4 5)
echo "The original array is: ${myarray[*]}"
arg1=$(echo ${myarray[*]})
result=($(arraydblr $arg1))
echo "The new array is: ${result[*]}"
function factorial {
if [ $1 -eq 1 ]
then
echo 1
else
local temp=$[ $1 - 1 ]
local result=$(factorial $temp)
echo $[ $result * $1 ]
fi
}
read -p "Enter value: " value
result=$(factorial $value)
echo "The factorial of $value is: $result"
$ cat myfuncs
# my script functions
function addem {
echo $[ $1 + $2 ]
}
$
. ./myfuncs
$ cat test14
#!/bin/bash
# using functions defined in a library file
. ./myfuncs
value1=10
value2=5
result1=$(addem $value1 $value2)
echo "The result of adding them is: $result1"
$
$ ./test14
The result of adding them is: 15
$ function divem { echo $[ $1 / $2 ]; }
$ divem 100 5
20
$ function doubleit { read -p "Enter value: " value; echo $[ $value * 2 ]; }
$
$ doubleit
Enter value: 20
40
$ function multem {
> echo $[ $1 * $2 ]
> }
$ multem 2 5
10
可以下载各种 shell 脚本函数并将其用于自己的应用程序中。
shtool 库提供了一些简单的 shell 脚本函数,可用于实现日常的shell 功能,比如处理临时文件和目录、格式化输出显示等。
下载及安装
shtool 软件包的下载地址如下:
ftp://ftp.gnu.org/gnu/shtool/shtool-2.0.8.tar.gz
tar -zxvf shtool-2.0.8.tar.gz
cd shtool-2.0.8
接下来就可以构建 shell 脚本库文件了。shtool 文件必须针对特定的 Linux 环境进行配置。配置过程必须使用标准的 configure 命令和 make 命令,这两个命令常用于 C 编程环境。要构建库文件,只需输入如下内容即可:
$ ./configure
$ make
也可以使用 make 命令测试这个库文件:
$ make test
Running test suite:
echo...........ok
mdate..........ok
...
OK: passed: 19/19
要完成安装,可以使用 make 命令的 install 选项。不过需要以 root 用户的身份运行该命令:
# make install
shtool 库提供了大量方便的函数。
函数 | 描述 |
---|---|
arx | 创建归档文件(包含一些扩展功能) |
echo | 显示字符串,并提供了一些扩展构件 |
fixperm | 改变目录树中的文件权限 |
install | 安装脚本或文件 |
mdate | 显示文件或目录的修改时间 |
mkdir | 创建一个或多个目录 |
mkln | 使用相对路径创建链接 |
mkshadow | 创建一棵阴影树(shadow tree) |
move | 带有替换功能的文件移动 |
path | 处理程序路径 |
platform | 显示平台标识 |
prop | 显示一个带有动画效果的进度条 |
rotate | 轮替(rotate)日志文件 |
scpp | 共享的 C 预处理器 |
slo | 根据库的类别, 分离出链接器选项 |
subst | 使用 sed 的替换操作 |
table | 以表格的形式显示由字段分隔(field-separated)的数据 |
tarball | 从文件和目录中创建 tar 文件 |
version | 创建版本信息文件 |
shtool [options] [function [options] [args]]
可以在命令行或 shell 脚本中直接使用 shtool 函数。下面是一个在 shell 脚本中使用platform 函数的例子:
$ cat test16
#!/bin/bash
shtool platform
$ ./test16
Ubuntu 20.04 (AMD64)
prop 函数使用\、 |、/和-字符创建了一个旋转的进度条,可以告诉 shell 脚本用户目前正在进行一些后台处理工作。要使用 prop 函数,只需将希望监看的输出管接到 shtool 脚本即可:
$ ls –al /usr/bin | shtool prop –p "waiting..."
waiting..
echo -e "1.\tDisplay disk space"
1. Display disk space
echo -en "\t\tEnter option: "
read -n 1 option
function diskspace {
clear
echo "This is where the diskspace commands will go"
}
function menu {
clear
echo
echo -e "\t\t\tSys Admin Menu\n"
echo -e "\t1. Display disk space"
echo -e "\t2. Display logged on users"
echo -e "\t3. Display memory usage"
echo -e "\t0. Exit program\n\n"
echo -en "\t\tEnter option: "
read -n 1 option
}
menu
case $option in
0)
break ;;
1)
diskspace ;;
2)
whoseon ;;
3)
memusage ;;
*)
clear
echo "Sorry, wrong selection";;
esac
$ cat menu1
#!/bin/bash
# simple script menu
function diskspace {
clear
df -k
}
function whoseon {
clear
who
}
function memusage {
clear
cat /proc/meminfo
}
function menu {
clear
echo
echo -e "\t\t\tSys Admin Menu\n"
echo -e "\t1. Display disk space"
echo -e "\t2. Display logged on users"
echo -e "\t3. Display memory usage"
echo -e "\t0. Exit program\n\n"
echo -en "\t\tEnter option: "
read -n 1 option
}
while [ 1 ]
do
menu
case $option in
0)
break ;;
1)
diskspace ;;
2)
whoseon ;;
3)
memusage ;;
*)
clear
echo "Sorry, wrong selection";;
esac
echo -en "\n\n\t\t\tHit any key to continue"
read -n 1 line
done
clear
$
select variable in list
do
commands
done
PS3="Enter option: "
select option in "Display disk space" "Display logged on users" "Display memory usage" "Exit program"
do
case $option in
"Exit program")
break ;;
"Display disk space")
diskspace ;;
"Display logged on users")
whoseon ;;
"Display memory usage")
memusage ;;
*)
clear
echo "Sorry, wrong selection";;
esac
done
clear
$ ./smenu1
1) Display disk space 3) Display memory usage
2) Display logged on users 4) Exit program
Enter option:
sudo apt-get install dialog
sudo dnf install dialog
略。
略。
略。
略。
略。
略。
略。
sed 编辑器被称作流编辑器(stream editor),与普通的交互式文本编辑器截然不同。在交互式文本编辑器(比如 Vim)中, 可以用键盘命令交互式地插入、删除或替换文本数据。流编辑器则是根据事先设计好的一组规则编辑数据流。
sed 编辑器根据命令来处理数据流中的数据,这些命令要么从命令行中输入,要么保存在命令文本文件中。 sed 编辑器可以执行下列操作:
在流编辑器匹配并针对一行数据执行所有命令之后,会读取下一行数据并重复这个过程。在流编辑器处理完数据流中的所有行后,就结束运行。由于命令是按顺序逐行执行的,因此 sed 编辑器只需对数据流处理一遍(one pass through)即可完成编辑操作。
sed 命令的格式如下:
sed options script file
sed 命令选项:
选项 | 描述 |
---|---|
-e commands | 在处理输入时,加入额外的 sed 命令 |
-f file | 在处理输入时,将 file 中指定的命令添加到已有的命令中 |
-n | 不产生命令输出,使用 p(print)命令完成输出 |
在命令行中定义编辑器命令
$ echo "This is a test" | sed 's/test/big test/'
This is a big test
$ sed 's/dog/cat/' data1.txt
在命令行中使用多个编辑器命令
$ sed -e 's/brown/red/; s/dog/cat/' data1.txt
$ sed -e '
> s/brown/green/
> s/fox/toad/
> s/dog/cat/' data1.txt
The quick green toad jumps over the lazy cat.
The quick green toad jumps over the lazy cat.
The quick green toad jumps over the lazy cat.
The quick green toad jumps over the lazy cat.
$
从文件中读取编辑器命令
$ cat script1.sed
s/brown/green/
s/fox/toad/
s/dog/cat/
$ sed -f script1.sed data1.txt
并不是所有的发行版中都默认安装了gawk。
gawk 是 Unix 中最初的 awk 的 GNU 版本。 gawk 比 sed 的流编辑提升了一个“段位”,它提供了一种编程语言,而不仅仅是编辑器命令。在 gawk 编程语言中,可以实现以下操作:
gawk 的报告生成能力多用于从大文本文件中提取数据并将其格式化成可读性报告。最完美的应用案例是格式化日志文件。在日志文件中找出错误行可不是一件容易事。 gawk 能够从日志文件中过滤出所需的数据,将其格式化,以便让重要的数据更易于阅读。
gawk 的基本格式如下。
gawk options program file
gawk 选项
选项 | 描述 |
---|---|
-F fs | 指定行中划分数据字段的字段分隔符 |
-f file | 从指定文件中读取 gawk 脚本代码 |
-v var=value | 定义 gawk 脚本中的变量及其默认值 |
-L [keyword] | 指定 gawk 的兼容模式或警告级别 |
gawk 的强大之处在于脚本。可以编写脚本来读取文本行中的数据,然后对其进行处理并显示,形成各种输出报告。
从命令行读取 gawk 脚本
$ gawk '{print "Hello World!"}'
使用数据字段变量
$ cat data2.txt
One line of test text.
Two lines of test text.
Three lines of test text.
$
$ gawk '{print $1}' data2.txt
One
Two
Three
$
$ gawk -F: '{print $1}' /etc/passwd
在脚本中使用多条命令
$ echo "My name is Rich" | gawk '{$4="Christine"; print $0}'
My name is Christine
$
$ gawk '{
> $4="Christine "
> print $0 }'
My name is Rich
My name is Christine
从文件中读取脚本
$ cat script2.gawk
{print $1 "'s home directory is " $6}
$
$ gawk -F: -f script2.gawk /etc/passwd
root's home directory is /root
...
$ cat script3.gawk
{
text = "'s home directory is "
print $1 text $6
}
$
在处理数据前运行脚本
$ gawk 'BEGIN {print "Hello World!"}'
Hello World!
$
$ cat data3.txt
Line 1
Line 2
Line 3
$
$ gawk 'BEGIN {print "The data3 File Contents:"}
> {print $0}' data3.txt
The data3 File Contents:
Line 1
Line 2
Line 3
$
在处理数据后运行脚本
$ gawk 'BEGIN {print "The data3 File Contents:"}
> {print $0}
> END {print "End of File"}' data3.txt
The data3 File Contents:
Line 1
Line 2
Line 3
End of File
$
整合在一起,从一个简单的数据文件中创建一份完整的报告:
$ cat script4.gawk
BEGIN {
print "The latest list of users and shells"
print "UserID \t Shell"
print "------- \t -------"
FS=":"
}
{
print $1 " \t " $7
}
END {
print "This concludes the listing"
}
$
$ gawk -f script4.gawk /etc/passwd
The latest list of users and shells
UserID Shell
-------- -------
root /bin/bash
daemon /usr/sbin/nologin
[...]
christine /bin/bash
sshd /usr/sbin/nologin
This concludes the listing
$
s/pattern/replacement/flags
$ cat data5.txt
This is a test line.
This is a different line.
$
$ sed -n 's/test/trial/p' data5.txt
This is a trial line.
$
$ sed 's/\/bin\/bash/\/bin\/csh/' /etc/passwd
$ sed 's!/bin/bash!/bin/csh!' /etc/passwd
[address]command
address {
command1
command2
command3
}
$ sed '2s/dog/cat/' data1.txt // 只修改了地址所指定的第二行的文本。
$ sed '2,3s/dog/cat/' data1.txt // 使用了行区间(第2行-第3行)
$ sed '2,$s/dog/cat/' data1.txt // 将命令应用于从某行开始到结尾的所有行,可以使用美元符号作为结尾行号
/pattern/command
$ grep /bin/bash /etc/passwd
root:x:0:0:root:/root:/bin/bash
christine:x:1001:1001::/home/christine:/bin/bash
rich:x:1002:1002::/home/rich:/bin/bash
$
$ sed '/rich/s/bash/csh/' /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
[...]
christine:x:1001:1001::/home/christine:/bin/bash
sshd:x:126:65534::/run/sshd:/usr/sbin/nologin
rich:x:1002:1002::/home/rich:/bin/csh
$
$ sed '2{
> s/fox/toad/
> s/dog/cat/
> }' data1.txt
The quick brown fox jumps over the lazy dog.
The quick brown toad jumps over the lazy cat.
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog.
$
$ sed '3,${
> s/brown/green/
> s/fox/toad/
> s/lazy/sleeping/
> }' data1.txt
$ sed 'd' data1.txt
$ cat data6.txt
This is line number 1.
This is line number 2.
This is the 3rd line.
This is the 4th line.
$ sed '3d' data6.txt
This is line number 1.
This is line number 2.
This is the 4th line.
$ sed '2,3d' data6.txt
This is line number 1.
This is the 4th line.
$ sed '3,$d' data6.txt
This is line number 1
This is line number 2.
$ sed '/number 1/d' data6.txt
This is line number 2.
This is the 3rd line.
This is the 4th line.
$
$ sed '/1/,/3/d' data6.txt
This is the 4th line.
$
$ cat data7.txt
This is line number 1.
This is line number 2.
This is the 3rd line.
This is the 4th line.
This is line number 1 again; we want to keep it.
This is more text we want to keep.
Last line in the file; we want to keep it.
$
$ sed '/1/,/3/d' data7.txt
This is the 4th line.
$
sed '[address]command\
new line '
$ echo "Test Line 2" | sed 'i\Test Line 1'
Test Line 1
Test Line 2
$
$ echo "Test Line 2" | sed 'a\Test Line 1'
Test Line 2
Test Line 1
$
$ echo "Test Line 2" | sed 'i\
> Test Line 1'
Test Line 1
Test Line 2
$
$ sed '3i\
> This is an inserted line.
> ' data6.txt
$ sed '$a\
> This line was added to the end of the file.
> ' data6.txt
$ sed '1i\
> This is an inserted line.\
> This is another inserted line.
> ' data6.txt
This is an inserted line.
This is another inserted line.
This is line number 1.
This is line number 2.
This is the 3rd line.
This is the 4th line.
$
$ sed '2c\
> This is a changed line of text.
> ' data6.txt
This is line number 1.
This is a changed line of text.
This is the 3rd line.
This is the 4th line.
$
$ sed '/3rd line/c\
> This is a changed line of text.
> ' data6.txt
$ cat data6.txt
This is line number 1.
This is line number 2.
This is the 3rd line.
This is the 4th line.
$
$ sed '2,3c\
> This is a changed line of text.
> ' data6.txt
This is line number 1.
This is a changed line of text.
This is the 4th line.
$
[address]y/inchars/outchars/
$ cat data9.txt
This is line 1.
This is line 2.
This is line 3.
This is line 4.
This is line 5.
This is line 1 again.
This is line 3 again.
This is the last file line.
$
$ sed 'y/123/789/' data9.txt
This is line 7.
This is line 8.
This is line 9.
This is line 4.
This is line 5.
This is line 7 again.
This is line 9 again.
This is the last file line.
$
$ echo "Test #1 of try #1." | sed 'y/123/678/'
Test #6 of try #6.
$ echo "this is a test" | sed 'p'
this is a test
this is a test
$
$ cat data6.txt
This is line number 1.
This is line number 2.
This is the 3rd line.
This is the 4th line.
$
$ sed -n '/3rd line/p' data6.txt
This is the 3rd line.
$
$ sed -n '2,3p' data6.txt
This is line number 2.
This is the 3rd line.
$
$ sed -n '/3/{
> p
> s/line/test/p
> }' data6.txt
This is the 3rd line.
This is the 3rd test.
$
$ sed '=' data1.txt
1
The quick brown fox jumps over the lazy dog.
2
The quick brown fox jumps over the lazy dog.
3
The quick brown fox jumps over the lazy dog.
4
The quick brown fox jumps over the lazy dog.
$
$ cat data7.txt
This is line number 1.
This is line number 2.
This is the 3rd line.
This is the 4th line.
This is line number 1 again; we want to keep it.
This is more text we want to keep.
Last line in the file; we want to keep it.
$
$ sed -n '/text/{
> =
> p
> }' data7.txt
6
This is more text we want to keep.
$
$ cat data10.txt
This line contains tabs.
This line does contain tabs.
This line contains an escape character.
$
$ sed -n 'l' data10.txt
This\tline\tcontains\ttabs.$
This line does contain tabs.$
This line contains an escape character. \a$
$
[address]w filename
$ sed '1,2w test.txt' data6.txt
This is line number 1.
This is line number 2.
This is the 3rd line.
This is the 4th line.
$
$ cat test.txt
This is line number 1.
This is line number 2.
$
$ cat data12.txt
Blum, R Browncoat
McGuiness, A Alliance
Bresnahan, C Browncoat
Harken, C Alliance
$
$ sed -n '/Browncoat/w Browncoats.txt' data12.txt
$
$ cat Browncoats.txt
Blum, R Browncoat
Bresnahan, C Browncoat
$
[address]r filename
$ cat data13.txt
This is an added line.
This is a second added line.
$
$ sed '3r data13.txt' data6.txt
This is line number 1.
This is line number 2.
This is the 3rd line.
This is an added line.
This is a second added line.
This is the 4th line.
$
$ sed '/number 2/r data13.txt' data6.txt
$ sed '$r data13.txt' data6.txt
$ cat notice.std
Would the following people:
LIST
please report to the ship's captain.
$
$ sed '/LIST/{
> r data12.txt
> d
> }' notice.std
Would the following people:
Blum, R Browncoat
McGuiness, A Alliance
Bresnahan, C Browncoat
Harken, C Alliance
please report to the ship's captain.
$
$ sed -sn '1s!/bin/sh!/bin/bash!' OldScripts/*.sh
$ sed -sn '1F;
> 1s!/bin/sh!/bin/bash!' OldScripts/*.sh
正则表达式是一种可供 Linux 工具过滤文本的自定义模板。 Linux 工具(比如 sed 或 gawk) 会在读取数据时使用正则表达式对数据进行模式匹配。如果数据匹配模式,它就会被接受并进行处理。如果数据不匹配模式,它就会被弃用。
正则表达式模式使用元字符来描述数据流中的一个或多个字符。
尽管在 Linux 世界中有很多不同的正则表达式引擎,但最流行的是以下两种。
大多数 Linux 工具至少符合 POSIX BRE 引擎规范,能够识别该规范定义的所有模式符号。有些工具(比如 sed)仅符合 BRE 引擎规范的一个子集。这是出于速度方面的考虑导致的,因为 sed 希望尽可能快地处理数据流中的文本。
POSIX ERE 引擎多见于依赖正则表达式过滤文本的编程语言中。它为常见模式(比如数字、单词以及字母数字字符)提供了高级模式符号和特殊符号。 gawk 使用 ERE 引擎来处理正则表达式。
最基本的 BRE 模式是匹配数据流中的文本字符。
正则表达式并不关心模式在数据流中出现的位置,也不在意模式出现了多少次。只要能匹配文本字符串中任意位置的模式,正则表达式就会将该字符串传回 Linux 工具。
正则表达式区分大小写。
在正则表达式中,无须写出整个单词。只要定义的文本出现在数据流中,正则表达式就能够匹配。
也无须局限于在正则表达式中只使用单个文本单词,空格和数字也是可以的。
$ echo "This is line number 1" | sed -n '/ber 1/p'
This is line number 1
$
$ echo "This is line number1" | sed -n '/ber 1/p'
$
$ cat data1
This is a normal line of text.
This is a line with too many spaces.
$ sed -n '/ /p' data1
This is a line with too many spaces.
$
.*[]^${}\+?|()
锚定行首
$ echo "The book store" | sed -n '/^book/p'
$
$ echo "Books are great" | sed -n '/^Book/p'
Books are great
$
锚定行尾
$ echo "This is a good book" | sed -n '/book$/p'
This is a good book
$ echo "This book is good" | sed -n '/book$/p'
$
$ echo "There are a lot of good books" | sed -n '/book$/p'
$
组合锚点
$ cat data4
this is a test of using both anchors
I said this is a test
this is a test
I'm sure this is a test.
$ sed -n '/^this is a test$/p' data4
this is a test
$
$ cat data5
This is one test line.
This is another test line.
$ sed '/^$/d' data5
This is one test line.
This is another test line.
$
$ sed -n '/[ch]at/p' data6
The cat is sleeping.
That is a very nice hat.
$
$ echo "Yes" | sed -n '/[Yy]es/p'
$ echo "Yes" | sed -n '/[Yy][Ee][Ss]/p'
$ sed -n '/[0123]/p' data7
$ cat data8
60633
46201
223001
4353
22203
$ sed -n '
>/[0123456789][0123456789][0123456789][0123456789][0123456789]/p
>' data8
60633
46201
223001
22203
$
$ sed -n '
> /^[0123456789][0123456789][0123456789][0123456789][0123456789]$/p
> ' data8
60633
46201
22203
$
$ sed -n '/[^ch]at/p' data6
This test is at line four.
$
$ sed -n '/^[0-9][0-9][0-9][0-9][0-9]$/p' data8
60633
46201
45902
$
$ sed -n '/[a-ch-m]at/p' data6
The cat is sleeping.
That is a very nice hat.
$
$ echo "I'm getting too fat." | sed -n '/[a-ch-m]at/p'
$
除了定义自己的字符组, BRE 还提供了一些特殊的字符组,以用来匹配特定类型的字符。
字符组 | 描述 |
---|---|
[[:alpha:]] | 匹配任意字母字符,无论是大写还是小写 |
[[:alnum:]] | 匹配任意字母数字字符, 0~9 、A~Z 或 a~z |
[[:blank:]] | 匹配空格或制表符 |
[[:digit:]] | 匹配 0~9 中的数字 |
[[:lower:]] | 匹配小写字母字符 a~z |
[[:print:]] | 匹配任意可打印字符 |
[[:punct:]] | 匹配标点符号 |
[[:space:]] | 匹配任意空白字符:空格、制表符、换行符、分页符(formfeed)、垂直制表符和回车符 |
[[:upper:]] | 匹配任意大写字母字符 A~Z |
特殊字符组在正则表达式中的用法和普通字符组一样:
$ echo "abc" | sed -n '/[[:digit:]]/p'
$
$ echo "abc" | sed -n '/[[:alpha:]]/p'
abc
$ echo "abc123" | sed -n '/[[:digit:]]/p'
abc123
$ echo "This is, a test" | sed -n '/[[:punct:]]/p'
This is, a test
$ echo "This is a test" | sed -n '/[[:punct:]]/p'
$
$ echo "I'm getting a color TV" | sed -n '/colou*r/p'
I'm getting a color TV
$ echo "I'm getting a colour TV" | sed -n '/colou*r/p'
I'm getting a colour TV
$
$ echo "this is a regular pattern expression" | sed -n '
> /regular.*expression/p'
this is a regular pattern expression
$
$ echo "bt" | sed -n '/b[ae]*t/p'
bt
$ echo "bat" | sed -n '/b[ae]*t/p'
bat
$ echo "bet" | sed -n '/b[ae]*t/p'
bet
$ echo "btt" | sed -n '/b[ae]*t/p'
btt
$ echo "baat" | sed -n '/b[ae]*t/p'
baat
$ echo "baaeeet" | sed -n '/b[ae]*t/p'
baaeeet
$ echo "baeeaeeat" | sed -n '/b[ae]*t/p'
baeeaeeat
$ echo "baakeeet" | sed -n '/b[ae]*t/p'
$
$ echo "bt" | gawk '/b[ae]?t/{print $0}'
bt
$ echo "beeet" | gawk '/be+t/{print $0}'
beeet
$ echo "bt" | gawk '/b[ae]+t/{print $0}'
$
$ echo "bt" | gawk --re-interval '/be{1}t/{print $0}'
$
$ echo "beet" | gawk --re-interval '/be{1,2}t/{print $0}'
beet
$ echo "bat" | gawk --re-interval '/b[ae]{1,2}t/{print $0}'
bat
expr1 |expr2|...
$ echo "The cat is asleep" | gawk '/cat|dog/{print $0}'
The cat is asleep
$ echo "The dog is asleep" | gawk '/cat|dog/{print $0}'
The dog is asleep
$ echo "The sheep is asleep" | gawk '/cat|dog/{print $0}'
$
$ echo "He has a hat." | gawk '/[ch]at|dog/{print $0}'
He has a hat.
$
$ echo "Sat" | gawk '/Sat(urday)?/{print $0}'
Sat
$ echo "Saturday" | gawk '/Sat(urday)?/{print $0}'
Saturday
$
$ echo "cat" | gawk '/(c|b)a(b|t)/{print $0}'
cat
$ cat countfiles
#!/bin/bash
# count number of files in your PATH
mypath=$(echo $PATH | sed 's/:/ /g')
count=0
for directory in $mypath
do
check=$(ls $directory)
for item in $check
do
count=$[ $count + 1 ]
done
echo "$directory - $count"
count=0
done
$ ./countfiles /usr/local/sbin - 0
/usr/local/bin - 2
/usr/sbin - 213
/usr/bin - 1427
/sbin - 186
/bin - 152
/usr/games - 5
/usr/local/games – 0
$
(123)456-7890
(123) 456-7890
123-456-7890
123.456.7890
^\(?[2-9][0-9]{2}\)?(| |-|\.)[0-9]{3}( |-|\.)[0-9]{4}$
拆解看:^\(? [2-9] [0-9]{2} \)? (| |-|\.) [0-9]{3} ( |-|\.) [0-9]{4}$
$ cat isphone
#!/bin/bash
# script to filter out bad phone numbers
gawk --re-interval '/^\(?[2-9][0-9]{2}\)?(| |-|\.)
[0-9]{3}( |-|\.)[0-9]{4}/{print $0}'
$
$ echo "317-555-1234" | ./isphone
317-555-1234
$ cat phonelist
000-000-0000
123-456-7890
...
$ cat phonelist | ./isphone
username@hostname
^([a-zA-Z0-9_\-\.\+]+)@([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]{2,5})$
拆解看:^([a-zA-Z0-9_\-\.\+]+) @ ([a-zA-Z0-9_\-\.]+) \. ([a-zA-Z]{2,5})$
sed 编辑器提供了 3 个可用于处理多行文本的特殊命令:
next 命令
单行 next 命令
$ cat data1.txt
Header Line
Data Line #1
End of Data Lines
$
$ sed '/Header/{n ; d}' data1.txt
Header Line
Data Line #1
End of Data Lines
$
合并文本行
$ cat data2.txt
Header Line
First Data Line
Second Data Line
End of Data Lines
$
$ sed '/First/{ N ; s/\n/ / }' data2.txt
Header Line
First Data Line Second Data Line
End of Data Lines
$
$ cat data3.txt
On Tuesday, the Linux System
Admin group meeting will be held.
All System Admins should attend.
Thank you for your cooperation.
$
$ sed 's/System Admin/DevOps Engineer/' data3.txt
On Tuesday, the Linux System
Admin group meeting will be held.
All DevOps Engineers should attend.
Thank you for your cooperation.
$
$ sed 'N ; s/System.Admin/DevOps Engineer/' data3.txt
On Tuesday, the Linux DevOps Engineer group meeting will be held.
All DevOps Engineers should attend.
Thank you for your cooperation.
$
$ sed 'N
> s/System\nAdmin/DevOps\nEngineer/
> s/System Admin/DevOps Engineer/
> ' data3.txt
On Tuesday, the Linux DevOps
Engineer group meeting will be held.
All DevOps Engineers should attend.
Thank you for your cooperation.
$
$ sed '
> s/System Admin/DevOps Engineer/
> N
> s/System\nAdmin/DevOps\nEngineer/
> ' data4.txt
$ sed 'N ; /System\nAdmin/d' data4.txt
All System Admins should attend.
$
$ sed 'N ; /System\nAdmin/D' data4.txt
Admin group meeting will be held.
All System Admins should attend.
$
$ cat data5.txt
Header Line
First Data Line
End of Data Lines
$
$ sed '/^$/{N ; /Header/D}' data5.txt
Header Line
First Data Line
End of Data Lines
$
$ sed -n 'N ; /System\nAdmin/P' data3.txt
On Tuesday, the Linux System
$
$ cat corruptData.txt
Header Line#
@
Data Line #1
Data Line #2#
@
End of Data Lines#
@
$
$ sed -n '
> N
> s/#\n@//
> P
> D
> ' corruptData.txt
Header Line
Data Line #1
Data Line #2
End of Data Lines
$
模式空间(pattern space )是一块活跃的缓冲区,在 sed 编辑器执行命令时保存着待检查的文本,但它并不是 sed 编辑器保存文本的唯一空间。
sed 编辑器还有另一块称作保留空间(hold space)的缓冲区。当你在处理模式空间中的某些行时,可以用保留空间临时保存部分行。
与保留空间相关的命令有 5 个,sed 编辑器的保留空间命令如下表:
命令 | 描述 |
---|---|
h | 将模式空间复制到保留空间 |
H | 将模式空间附加到保留空间 |
g | 将保留空间复制到模式空间 |
G | 将保留空间附加到模式空间 |
x | 交换模式空间和保留空间的内容 |
这些命令可以将文本从模式空间复制到保留空间,以便清空模式空间,载入其他要处理的字符串。
通常, 在使用 h 命令或 H 命令将字符串移入保留空间后,最终还是要用 g 命令、 G 命令或 x 命令将保存的字符串移回模式空间(否则,一开始就不用考虑保存的问题)。
例子,如何用 h 命令和 g 命令在缓冲空间之间移动数据:
$ cat data2.txt
Header Line
First Data Line
Second Data Line
End of Data Lines
$
$ sed -n '/First/ {
> h ; p ;
> n ; p ;
> g ; p }
> ' data2.txt
First Data Line
Second Data Line
First Data Line
$
通过保留空间来回移动文本行,可以强制 First Data Line 输出在 Second Data Line
之后。如果去掉第一个 p 命令,则可以将这两行以相反的顺序输出:
$ sed -n '/First/ {
> h ;
> n ; p
> g ; p }
> ' data2.txt
Second Data Line
First Data Line
$
$ sed -n '/Header/!p' data2.txt
First Data Line
Second Data Line
End of Data Lines
$
$ cat data2.txt
Header Line
First Data Line
Second Data Line
End of Data Lines
$
$ sed -n '{1!G ; h ; $p }' data2.txt
End of Data Lines
Second Data Line
First Data Line
Header Line
$
sed 编辑器还提供了一种方法,这种方法可以基于地址、地址模式或地址区间排除一整段命令。这允许你只对数据流中的特定行执行部分命令。
分支(b)命令的格式如下:
[address]b [label]
下面这个例子使用了分支命令的 address 参数,但未指定 label:
$ cat data2.txt
Header Line
First Data Line
Second Data Line
End of Data Lines
$
$ sed '{2,3b ;
> s/Line/Replacement/}
> ' data2.txt
Header Replacement
First Data Line
Second Data Line
End of Data Replacements
$
如果不想跳到脚本末尾,可以定义 label 参数,指定分支命令要跳转到的位置。标签以冒号开始,最多可以有 7 个字符:
:label2
$ sed '{/First/b jump1 ;
> s/Line/Replacement/
> :jump1
> s/Line/Jump Replacement/}
> ' data2.txt
Header Replacement
First Data Jump Replacement
Second Data Replacement
End of Data Replacements
$
也可以跳转到靠前的标签,达到循环的效果:
$ echo "This, is, a, test, to, remove, commas." |
> sed -n {'
> :start
> s/,//1p
> /,/b start
> }'
[address]t [label]
$ sed '{s/First/Matched/ ; t
> s/Line/Replacement/}
> ' data2.txt
Header Replacement
Matched Data Line
Second Data Replacement
End of Data Replacements
$
$ echo "The cat sleeps in his hat." |
> sed 's/.at/"&"/g'
The "cat" sleeps in his "hat".
$
$ echo "The Guide to Programming" |
> sed '
> s/\(Guide to\) Programming/\1 DevOps/'
The Guide to DevOps
$
$ echo "That furry cat is pretty." |
> sed 's/furry \(.at\)/\1/'
That cat is pretty.
$
$ echo "That furry hat is pretty." |
> sed 's/furry \(.at\)/\1/'
That hat is pretty.
$
$ echo "1234567" | sed '{
> :start
> s/\(.*[0-9]\)\([0-9]\{3\}\)/\1,\2/
> t start}'
1,234,567
$
.*[0-9]
[0-9]{3}
$ cat reverse.sh
#!/bin/bash
# Shell wrapper for sed editor script
# to reverse test file lines.
#
sed -n '{1!G; h; $p}' $1
#
exit
$
$ ./reverse.sh data2.txt
$ cat fact.sh
#!/bin/bash
# Shell wrapper for sed editor script
# to calculate a factorial, and
# format the result with commas.
#
factorial=1
counter=1
number=$1
#
while [ $counter -le $number ]
do
factorial=$[ $factorial * $counter ]
counter=$[ $counter + 1 ]
done
#
result=$(echo $factorial |
sed '{
:start
s/\(.*[0-9]\)\([0-9]\{3\}\)/\1,\2/
t start
}')
#
echo "The result is $result"
#
exit
$
$ ./fact.sh 20
The result is 2,432,902,008,176,640,000
$
$ sed 'G' data2.txt
Header Line
First Data Line
Second Data Line
End of Data Lines
$
$ sed '$!G' data2.txt
Header Line
First Data Line
Second Data Line
End of Data Lines
$
/^$/d
$ sed '/^$/d ; $!G' data6.txt
Line one.
Line two.
Line three.
Line four.
$
$ sed '=' data2.txt | sed 'N; s/\n/ /'
1 Header Line
2 First Data Line
3 Second Data Line
4 End of Data Lines
$
$ sed -n '$p' data2.txt
End of Data Lines
$
$ cat data7.txt
Line1
Line2
Line3
Line4
Line5
Line6
Line7
Line1
Line2
Line3
Line4
Line5
Line6
Line7
Line8
Line9
Line10
Line11
Line12
Line13
Line14
Line15
$
$ sed '{
> :start
> $q ; N ; 11,$D
> b start
> }' data7.txt
Line6
Line7
Line8
Line9
Line10
Line11
Line12
Line13
Line14
Line15
$
删除连续的空行
$ sed '/./,/^$/!d' data8.txt
删除开头的空行
$ sed '/./,$!d' data9.txt
删除结尾的空行
$ sed '{
> :start
> /^\n*$/{$d; N; b start}
> }' data10.txt
$ sed 's/<[^>]*>//g' data11.txt
$ sed 's/<[^>]*>//g ; /^$/d' data11.txt
字段和记录分隔符变量
数据字段变量允许使用美元符号($)和字段在记录中的位置值来引用对应的字段。因此,要引用记录中的第一个数据字段,就用变量$1;要引用第二个数据字段,就用$2,以此类推。
数据字段由字段分隔符划定。在默认情况下,字段分隔符是一个空白字符,也就是空格或者制表符。
有一组内建变量可以控制 gawk 对输入数据和输出数据中字段和记录的处理方式。gawk 数据字段和记录变量如下表:
变量 | 描述 |
---|---|
FIELDWIDTHS | 由空格分隔的一列数字, 定义了每个数据字段的确切宽度 |
FS | 输入字段分隔符 |
RS | 输入记录分隔符 |
OFS | 输出字段分隔符 |
ORS | 输出记录分隔符 |
变量 OFS 用于 print 命令的输出。在默认情况下, gawk 会将 OFS 变量的值设置为一个空格。
命令:print $1,$2,$3
输出:field1 field2 field3
print 命令会自动将 OFS 变量的值置于输出的每个字段之间。通过设置 OFS 变量,可以在输出中用任意字符串来分隔字段。
FIELDWIDTHS 变量可以不通过字段分隔符读取记录。有些应用程序并没有使用字段分隔符,而是将数据放置在记录中的特定列。在这种情况下,必须设定 FIELDWIDTHS 变量来匹配数据在记录中的位置。一旦设置了 FIELDWIDTHS 变量, gawk 就会忽略 FS 变量, 并根据提供的字段宽度来计算字段。
一定要记住,一旦设定了 FIELDWIDTHS 变量的值,就不能再改动了。这种方法并不适用于变长的数据字段。
变量 RS 和 ORS 定义了 gawk 对数据流中记录的处理方式。在默认情况下, gawk 会将 RS 和 ORS 设置为换行符。默认的 RS 值表明,输入数据流中的每行文本就是一条记录。
数据变量
更多的 gawk 内建变量
变量 | 描述 |
---|---|
ARGC | 命令行参数的数量 |
ARGIND | 当前处理的文件在 ARGV 中的索引 |
ARGV | 包含命令行参数的数组 |
CONVFMT | 数字的转换格式(参见 printf 语句),默认值为%.6g |
ENVIRON | 当前 shell 环境变量及其值组成的关联数组 |
ERRNO | 当读取或关闭输入文件发生错误时的系统错误号 |
FILENAME | 用作 gawk 输入的数据文件的名称 |
FNR | 当前数据文件中的记录数 |
IGNORECASE | 设成非 0 值时,忽略 gawk 命令中出现的字符串的大小写 |
NF | 数据文件中的字段总数 |
NR | 已处理的输入记录数 |
OFMT | 数字的输出显示格式。默认值为%.6g.,以浮点数或科学计数法显示,以较短者为准,最多使用 6 位小数 |
RLENGTH | 由 match 函数所匹配的子串的长度 |
RSTART | 由 match 函数所匹配的子串的起始位置 |
gawk 并不会将程序脚本视为命令行参数的一部分:
$ gawk 'BEGIN{print ARGC,ARGV[1]}' data1
2 data1
$
跟 shell 变量不同,在脚本中引用 gawk 变量时,变量名前不用加美元符号。
ENVIRON 使用关联数组来提取 shell 环境变量。关联数组用文本(而非数值)作为数组索引。
数组索引中的文本是 shell 环境变量名, 对应的数组元素值是 shell 环境变量的值。
$ gawk '
> BEGIN{
> print ENVIRON["HOME"]
> print ENVIRON["PATH"]
> }'
/home/rich
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
$
NF 变量可以让你在不知道具体位置的情况下引用记录中的最后一个数据字段。NF 变量含有数据文件中最后一个字段的编号。可以在 NF 变量之前加上美元符号,将其用作字段变量。
FNR 变量包含当前数据文件中已处理过的记录数, NR 变量则包含已处理过的记录总数。因此,如果只使用一个数据文件作为输入, 那么 FNR 和 NR 的值是相同的; 如果使用多个数据文件作为输入,那么 FNR 的值会在处理每个数据文件时被重置, NR 的值则会继续计数直到处理完所有的数据文件。
gawk 自定义变量的名称由任意数量的字母、数字和下划线组成,但不能以数字开头。gawk 变量名区分大小写。
在脚本中给变量赋值
$ gawk '
> BEGIN{
> testing="This is a test"
> print testing
> testing=45
> print testing
> }'
This is a test
45
$
在命令行中给变量赋值
$ cat script1
BEGIN{FS=","}
{print $n}
$ gawk -f script1 n=2 data1
data12
data22
data32
$ gawk -f script1 n=3 data1
data13
data23
data33
$
$ cat script2
BEGIN{print "The starting value is",n; FS=","}
{print $n}
$ gawk -f script2 n=3 data1
The starting value is
data13
data23
data33
$
$ gawk -v n=3 -f script2 data1
The starting value is 3
data13
data23
data33
$
var[index] = element
例如,capital["Illinois"] = "Springfield"
$ gawk 'BEGIN{
> capital["Illinois"] = "Springfield"
> print capital["Illinois"]
> }'
Springfield
$
for (var in array)
{
statements
}
delete array[index]
$ gawk 'BEGIN{
> var["a"] = 1
> var["g"] = 2
> for (test in var)
> {
> print "Index:",test," - Value:",var[test]
> }
> delete var["g"]
> print "---"
> for (test in var)
> print "Index:",test," - Value:",var[test]
> }'
Index: a - Value: 1
Index: g - Value: 2
---
Index: a - Value: 1
$
$ gawk 'BEGIN{FS=","} /11/{print $1}' data1
data11
$
$ gawk 'BEGIN{FS=","} /,d/{print $1}' data1
data11
data21
data31
$
$1 ~ /^data/
$ gawk 'BEGIN{FS=","} $2 ~ /^data2/{print $0}' data1
data21,data22,data23,data24,data25
$
$ gawk -F: '$1 ~ /rich/{print $1,$NF}' /etc/passwd
rich /bin/bash
$
$1 !~ /expression/
$ gawk -F: '$4 == 0{print $1}' /etc/passwd
root
$
$ gawk -F, '$1 == "data"{print $1}' data1
$
$ gawk -F, '$1 == "data11"{print $1}' data1
$ data11
gawk 编程语言支持常见的结构化编程命令。
if 语句
if (condition)
statement1
也可以写在一行中:
if (condition) statement1
if (condition) statement1; else statement2
while (condition)
{
statements
}
do
{
statements
} while (condition)
for( variable assignment; condition; iteration process)
$ gawk '{
> total = 0
> for (i = 1; i < 4; i++)
> {
> total += $i
> }
> avg = total / 3
> print "Average:",avg
> }' data5
Average: 128.333
Average: 137.667
Average: 176.667
$
使用格式化打印命令 printf。如果熟悉 C 语言编程, 那么 gawk 中 printf 命 令的用法也是一样,允许指定具体如何显示数据的指令。
printf 命令的格式如下:
printf "format string", var1, var2
格式说明符的格式如下:
%[modifier]control-letter
格式说明符的控制字母
控制字母 | 描述 |
---|---|
c | 将数字作为 ASCII 字符显示 |
d | 显示整数值 |
i | 显示整数值(和 d 一样) |
e | 用科学计数法显示数字 |
f | 显示浮点值 |
g | 用科学计数法或浮点数显示(较短的格式优先) |
o | 显示八进制值 |
s | 显示字符串 |
x | 显示十六进制值 |
X | 显示十六进制值,但用大写字母 A~F |
如果要显示一个字符串变量,可以用格式说明符%s。如果要显示一个整数值,可以用%d 或%i( %d 是十进制数的 C 语言风格显示方式)。如果要用科学计数法显示很大的值, 可以使用格式说明符%e。
除了控制字母,还有 3 种修饰符可以进一步控制输出。
注意,你需要在 printf 命令的末尾手动添加换行符,以便生成新行,否则,printf 命令会继续在同一行打印后续输出。
例子:
$ gawk 'BEGIN{FS="\n"; RS=""} {printf "%16s %s\n", $1, $4}' data2
Ima Test (312)555-1234
Frank Tester (317)555-9876
Haley Example (313)555-4938
$
$ gawk 'BEGIN{FS="\n"; RS=""} {printf "%-16s %s\n", $1, $4}' data2
Ima Test (312)555-1234
Frank Tester (317)555-9876
Haley Example (313)555-4938
$
printf "Average: %5.1f\n",avg
gawk 编程语言提供了不少内置函数,以用于执行一些常见的数学、字符串以及时间运算。
数学函数
gawk 数学函数
函数 | 描述 |
---|---|
atan2(x, y) | x/y 的反正切, x 和 y 以弧度为单位 |
cos(x) | x 的余弦, x 以弧度为单位 |
exp(x) | x 的指数 |
int(x) | x 的整数部分, 取靠近 0 一侧的值 |
log(x) | x 的自然对数 |
rand( ) | 比 0大且比 1 小的随机浮点值 |
sin(x) | x 的正弦, x 以弧度为单位 |
sqrt(x) | x 的平方根 |
srand(x) | 为计算随机数指定一个种子值 |
int() 函数会生成一个值的整数部分,但并不会四舍五入取近似值。它的做法更像其他编程语言中的 floor 函数,会生成该值和 0 之间最接近该值的整数。
rand()函数会返回一个随机数,但这个随机数只在 0 和 1 之间(不包括 0 或 1)。要得到更大的数,就需要放大返回值。产生较大随机整数的常见方法是综合运用函数 rand()和 int()创建一个算法:
x = int(10 * rand())
在使用一些数学函数时要小心,因为gawk 编程语言对于其能够处理的数值有一个限定区间。如果超出了这个区间,就会得到一条错误消息:
$ gawk 'BEGIN{x=exp(1000); print x}'
gawk: warning: exp argument 1000 is out of range
inf
$
gawk 还支持一些按位操作数据的函数。
gawk 字符串函数
函数 | 描述 |
---|---|
asort(s [,d]) | 将数组 s 按照数组元素值排序。索引会被替换成表示新顺序的连续数字。另外,如果指定了 d,则排序后的数组会被保存在数组 d 中 |
asorti(s [,d]) | 将数组 s 按索引排序。生成的数组会将索引作为数组元素值,用连续数字索引表明排序顺序。另外,如果指定了 d,则排序后的数组会被保存在数组 d 中 |
gensub(r, s, h [,t]) | 针对变量$0或目标字符串 t(如果提供了的话)来匹配正则表达式 r。如果 h 是一个以 g 或 G 开头的字符串,就用 s 替换匹配的文本。如果 h 是一个数字,则表示要替换 r 的第 h 处匹配 |
gsub(r, s [,t]) | 针对变量$0或目标字符串 t(如果提供了的话) 来匹配正则表达式 r。如果找到了,就将所有的匹配之处全部替换成字符串 s |
index(s, t) | 返回字符串 t 在字符串 s 中的索引位置;如果没找到,则返回 0 |
length([s]) | 返回字符串 s 的长度;如果没有指定,则返回$0 的长度 |
match(s, r [,a]) | 返回正则表达式 r 在字符串 s 中匹配位置的索引。如果指定了数组 a,则将 s 的 匹配部分保存在该数组中 |
split(s, a [,r]) | 将 s 以 FS(字段分隔符)或正则表达式 r(如果指定了的话)分割并放入数组 a 中。返回分割后的字段总数 |
sprintf(format, variables) | 用提供的 format 和 variables 返回一个类似于 printf 输出的字符串 |
sub(r, s [,t]) | 在变量$0 或目标字符串 t 中查找匹配正则表达式 r 的部分。如果找到了,就用字符串 s 替换第一处匹配 |
substr(s, i [,n]) | 返回 s 中从索引 i 开始、长度为 n 的子串。如果未提供 n,则返回 s 中剩下的部分 |
tolower(s) | 将 s 中的所有字符都转换成小写 |
toupper(s) | 将 s 中的所有字符都转换成大写 |
asort 和 asorti 是新加入的 gawk 函数,允许基于数据元素值(asort)或索引(asorti)对数组变量进行排序。这里有个使用 asort 的例子:
$ gawk 'BEGIN{
> var["a"] = 1
> var["g"] = 2
> var["m"] = 3
> var["u"] = 4
> asort(var, test)
> for (i in test)
> print "Index:",i," - value:",test[i]
> }'
Index: 4 - value: 4
Index: 1 - value: 1
Index: 2 - value: 2
Index: 3 - value: 3
split 函数是将数据字段放入数组以供进一步处理的好办法:
$ gawk 'BEGIN{ FS=","}{
> split($0, var)
> print var[1], var[5]
> }' data1
data11 data15
data21 data25
data31 data35
$
gawk 的时间函数
函数 | 描述 |
---|---|
mktime(datespec) | 将一个按 YYYY MM DD HH MM SS [DST]格式指定的日期转换成时间戳 |
strftime(format [, timestamp]) | 将当前时间的时间戳或 timestamp (如果提供了的话)转化为格式化日期 (采用 shell 命令 date 的格式) |
systime() | 返回当前时间的时间戳 |
时间戳( timestamp )是自 1970-01-01 00:00:00 UTC 到现在,以秒为单位的计数,通常称为纪元时(epoch time)。systime()函数的返回值也是这种形式。
时间函数多用于处理日志文件。日志文件中通常含有需要进行比较的日期。通过将日期的文本表示形式转换成纪元时(自 1970-01-01 00:00:00 UTC 到现在的秒数),可以轻松地比较日期。
在 gawk 脚本中使用时间函数的例子:
$ gawk 'BEGIN{
> date = systime()
> day = strftime("%A, %B %d, %Y", date)
> print day
> }'
Friday, December 26, 2014
$
除了 gawk 中的内建函数, 还可以在 gawk 脚本中创建自定义函数。
定义函数
function name([variables])
{
statements
}
function myrand(limit)
{
return int(limit * rand())
}
x = myrand(100)
$ gawk '
> function myprint()
> {
> printf "%-16s - %s\n", $1, $4
> }
> BEGIN{FS="\n"; RS=""}
> {
> myprint()
> }' data2
Ima Test - (312)555-1234
Frank Tester - (317)555-9876
Haley Example - (313)555-4938
$
$ cat funclib
function myprint()
{
printf "%-16s - %s\n", $1, $4
}
function myrand(limit)
{
return int(limit * rand())
}
function printthird()
{
print $3
}
$
$ cat script4
BEGIN{ FS="\n"; RS=""}
{
myprint()
}
$ gawk -f funclib -f script4 data2
Ima Test - (312)555-1234
Frank Tester - (317)555-9876
Haley Example - (313)555-4938
$
$ cat /etc/passwd | grep rich
rich:x:1000:1000:Rich,,,:/home/rich:/bin/bash
$
$ ls -al /bin/sh
lrwxrwxrwx 1 root root 4 Jul 21 08:10 /bin/sh -> dash
$
略。
略。
选项 | 描述 |
---|---|
-c | 只执行指定的命令,然后退出 |
-i | 作为交互式 shell 启动,提供命令行提示符 |
-s | 强制 shell 从 STDIN 读取命令 |
-o | 指定命令行选项 |
zsh shell 的独到之处在于能够扩展 shell 的内建命令。
zsh 核心内建命令
命令 | 描述 |
---|---|
alias | 为命令及参数定义一个替代性名称 |
autoload | 将 shell 函数预加载到内存中以便快速访问 |
bg | 以后台模式执行作业 |
bindkey | 将组合键和命令绑定到一起 |
builtin | 执行指定的内建命令,而非同名的可执行文件 |
bye | 同 exit |
cd | 切换当前工作目录 |
chdir | 切换当前工作目录 |
command | 执行以外部可执行文件为形式的命令,而非同名的函数或内建命令 |
declare | 设置变量的数据类型(同 typeset) |
dirs | 显示目录栈的内容 |
disable | 临时禁用指定的哈希表元素 |
disown | 从作业表中移除指定的作业 |
echo | 显示变量和文本 |
emulate | 用 zsh 来仿真另一种 shell,比如 Bourne、Korn 或 C shell |
enable | 启用指定的哈希表元素 |
eval | 在当前 shell 进程环境中执行指定的命令和参数 |
exec | 执行指定的命令和参数来替换当前 shell 进程 |
exit | 退出 shell 并返回指定的退出状态码。如果未指定,则使用最后一个命令的退出状态码 |
export | 允许在子 shell 进程中使用指定的环境变量 |
false | 返回退出状态码 1 |
fc | 从历史记录中选择某个范围内的命令 |
fg | 以前台模式执行指定的作业 |
float | 将指定变量设为浮点类型 |
functions | 将指定名称设为函数 |
getln | 从缓冲栈中读取下一个值并将其放入指定变量 |
getopts | 提取命令行参数中的下一个有效选项并将其放入指定变量 |
hash | 直接修改命令哈希表的内容 |
history | 列出历史记录文件中的命令 |
integer | 将指定变量设为整数类型 |
jobs | 列出指定作业的信息,或是分配给 shell 进程的所有作业 |
kill | 向指定进程或作业发送信号(默认为 SIGTERM) |
let | 执行数学运算并将结果赋给变量 |
limit | 设置或显示资源限制 |
local | 将指定变量设为局部变量 |
log | 显示受 watch 参数影响的所有当前登录用户 |
logout | 同 exit,但仅适用于当前 shell 为登录 shell |
popd | 从目录栈中删除下一项 |
显示变量和文本 | |
printf | 用 C 语言风格的格式字符串来显示变量和文本 |
pushd | 改变当前工作目录,并将上一个目录放入目录栈 |
pushln | 将指定参数放入编辑缓冲栈 |
pwd | 显示当前工作目录的完整路径 |
read | 读取一行并用 IFS 变量将字段赋给指定变量 |
readonly | 将值赋给只读变量 |
rehash | 重建命令哈希表 |
set | 为 shell 设置选项或位置参数 |
setopt | 为 shell 设置选项 |
shift | 读取并删除第一个位置参数,然后将剩余的参数向前移动一个位置 |
source | 找到指定文件并将其内容复制到当前位置 |
suspend | 挂起 shell 的执行,直至收到 SIGCONT 信号 |
test | 如果指定条件为 TRUE,就返回退出状态码 0 |
times | 显示当前 shell 以及 shell 中所有运行进程的累计用户时间和系统时间 |
trap | 阻断 shell 处理指定信号, 如果收到信号则执行指定命令 |
true | 返回退出状态码 0 |
ttyctl | 锁定和解锁显示 |
type | 显示 shell 会如何解释指定的命令 |
typeset | 设置或显示变量的属性 |
ulimit | 设置或显示 shell 或 shell 中运行进程的资源限制 |
umask | 设置或显示创建文件和目录的默认权限 |
unalias | 删除指定的命令别名 |
unfunction | 删除指定的已定义函数 |
unhash | 删除哈希表中的指定命令 |
unlimit | 取消指定的资源限制 |
unset | 删除指定的变量属性 |
unsetopt | 禁用指定的 shell 选项 |
wait | 等待指定的作业或进程完成 |
whence | 显示 shell 如何解释指定命令 |
where | 显示指定命令的路径(如果 shell 能找到的话) |
which | 用 csh shell 风格的输出显示指定命令的路径 |
zcompile | 编译指定的函数或脚本, 提高自动加载速度 |
zmodload | 对可加载 zsh 模块执行特定操作 |
有大量的模块可以为 zsh shell 提供额外的内建命令。一些流行的 zsh 模块如下表:
模块 | 描述 |
---|---|
zsh/datetime | 附加的日期和时间命令及变量 |
zsh/files | 基础的文件处理命令 |
zsh/mapfile | 通过关联数组来访问外部文件 |
zsh/mathfunc | 附加的科学函数 |
zsh/pcre | 扩展正则表达式库 |
zsh/net/socket | Unix 域套接字支持 |
zsh/stat | 访问 stat 系统调用来提供系统的统计状况 |
zsh/system | 各种底层系统功能的接口 |
zsh/net/tcp | 访问 TCP 套接字 |
zsh/zftp | FTP 客户端命令 |
zsh/zselect | 阻塞,直到文件描述符就绪才返回 |
zsh/zutil | 各种 shell 实用工具 |
zmodload 命令是 zsh 模块的管理接口。你可以在zsh shell 会话中使用该命令查看、添加或删除模块。
不加任何参数的 zmodload 命令会显示 zsh shell 中当前已安装的模块:
% zmodload
zsh/complete
zsh/files
zsh/main
zsh/parameter
zsh/stat
zsh/terminfo
zsh/zle
zsh/zutil
%
不同的 zsh shell 实现在默认情况下包含了不同的模块。要添加新模块,只需在 zmodload 命令行中指定模块名称即可:
% zmodload zsh/net/tcp
%
将 zmodload 命令放入$HOME/.zshrc 启动文件是一种常见的做法,这样在 zsh 启动时就会自动加载常用的模块。
% let value1=" 4 * 5.1 / 3.2 "
% echo $value1
6.3749999999999991
% printf "%6.3f\n" $value1
6.375
%
% value1=$(( 4 * 5.1 ))
% (( value2 = 4 * 5.1 ))
% printf "%6.3f\n" $value1 $value2
20.400
20.400
%
% value=10
% value2=$(( $value1 / 3 ))
% echo $value2
3
%
% value=10.
% value2=$(( $value1 / 3. ))
% echo $value2
3.3333333333333335
%
% value1=$(( sqrt(9) ))
zsh: unknown function: sqrt
% zmodload zsh/mathfunc
% value1=$(( sqrt(9) ))
% echo $value1
3.
%
repeat param
do
commands
done
value1=$(( 10 / 2 ))
repeat $value1
do
echo "This is a test"
done
$ ./test4
This is a test
This is a test
This is a test
This is a test
This is a test
% function functest1 {
> echo "This is the test1 function"
}
% functest2() {
> echo "This is the test2 function"
}
% functest1
This is the test1 function
% functest2
This is the test2 function
%
server$ zsh
server% zmodload zsh/net/tcp
server% ztcp -l 8000
server% listen=$REPLY
server% ztcp -a $listen
client$ zsh
client% zmodload zsh/net/tcp
client% ztcp localhost 8000
client% remote=$REPLY
client%
server% remote=$REPLY
client% print 'This is a test message' >&$remote
client%
server% read -r data <&$remote; print -r $data
This is a test message
server%
server% ztcp -c $listen
server% ztcp -c $remote
client% ztcp -c $remote
$ tar -cf archive.tar /home/christine/Project/*.*
tar: Removing leading `/' from member names
tar: Removing leading `/' from hard link targets
$
$ ls -og archive.tar
-rw-rw-r-- 1 112640 Aug 6 13:33 archive.tar
$ tar -cf archive.tar Project/*.* 2>/dev/null
$
$ tar -zcf archive.tgz Project/*.* 2>/dev/null
$
$ ls -hog archive.tgz
-rw-rw-r-- 1 11K Aug 6 13:40 archive.tgz
exec 0 < $config_file
read file_name
while [ $? -eq 0 ]
do
[...]
read file_name
done
$ cut -d: -f7 /etc/passwd
/bin/bash
/usr/sbin/nologin
/usr/sbin/nologin
/usr/sbin/nologin
[...]
/bin/false
/bin/bash
/usr/sbin/nologin
/bin/bash
/usr/sbin/nologin
/bin/bash
$
Git 通常并非默认安装项,在设置 Git 环境之前,需要自行安装 git 软件包。
在 CentOS Linux 发行版中安装 Git 的过程如下:
$ sudo dnf install git
...
Complete!
$ which git
/usr/bin/git
在 Ubuntu Linux 发行版中安装 Git 的过程如下:
$ sudo apt install git
...
Processing triggers for man-db (2.9.1-1) ...
$ which git
/usr/bin/git
安装好 git 软件包之后,为新的脚本项目设置 Git 环境涉及以下 4 个基本步骤:
具体步骤如下:
1、首先,创建工作目录。在本地主目录下创建一个子目录即可:
$ mkdir MWGuard
$
$ cd MWGuard/
$
$ pwd
/home/christine/MWGuard
$
2、然后,在工作目录中初始化.git/子目录。这要用到 git init 命令:
$ git init
Initialized empty Git repository in /home/christine/MWGuard/.git/
$
$ ls -ld .git
drwxrwxr-x 7 christine christine 4096 Aug 24 14:49 .git
$
3、如果是首次使用,则设置name和email:
$ git config --global user.name "Christine Bresnahan"
$
$ git config --global user.email "cbresn1723@gmail.com"
$
$ git config --get user.name
Christine Bresnahan
$
$ git config --get user.email
cbresn1723@gmail.com
$
4、配置好本地 Git 环境之后,就可以建立项目的远程仓库了。建立好项目的远程仓库之后,需要把仓库地址记下来。随后向远程仓库发送项目文件时, 要 用到这个地址。
要查看这些文件中的各种配置信息, 可以使用 git config --list 命令:
$ git config --list
user.name=Christine Bresnahan
user.email=cbresn1723@gmail.com
core.repositoryformatversion=0
core.filemode=true
core.bare=false
core.logallrefupdates=true
$ cat /home/christine/.gitconfig
[user]
name = Christine Bresnahan
email = cbresn1723@gmail.com
$
$ cat /home/christine/MWGuard/.git/config
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
$
尽管 Git 能够处理任意文件类型,但其相关工具主要针对的是纯文本文件,比如 bash shell 脚本。因此要注意,不是所有的 git 工具都能用于非文本文件。
建立好 Git 环境之后,就可以使用它的各种组织功能了。这也有 4 个基本步骤:
例子:
1、创建好脚本之后, 使用 git add 命令将其添加到暂存区(索引)。由于该脚本目前不在工作 目录/home/christine/MWGuard 中,因此需要先把它复制过来。然后切换到工作目录(通过 pwd 命令确认),执行 git add 命令:
$ pwd
/home/christine/scripts
$
$ cp MyGitExampleScript.sh /home/christine/MWGuard/
$
$ cd /home/christine/MWGuard/
$
$ pwd
/home/christine/MWGuard
$
$ ls *.sh
MyGitExampleScript.sh
$
$ git add MyGitExampleScript.sh
$
$ git status
[…]
No commits yet
Changes to be committed:
(use "git rm --cached ..." to unstage)
new file: MyGitExampleScript.sh
$
2、下一步是使用 git commit 命令将项目提交至本地仓库。可以使用-m 选项来添加注释,这有助于记录( documenting )提交。
$ git commit -m "Initial Commit"
[…] Initial Commit
1 file changed, 5 insertions(+)
create mode 100644 MyGitExampleScript.sh
$
$ cat .git/COMMIT_EDITMSG
Initial Commit
$
$ git status
[…]
nothing to commit, working tree clean
$
3、创建 README.md 文件,将其加入暂存区并提交到本地仓库。
$ pwd
/home/christine/MWGuard
$
$ ls
MyGitExampleScript.sh
$
$ echo "# Milky Way Guardian" > README.md
$ echo "## Script Project" >> README.md
$
$ cat README.md
# Milky Way Guardian
## Script Project
$
$ git add README.md
$
$ git status
[...]
Changes to be committed:
(use "git restore --staged ..." to unstage)
new file: README.md
$
$ git commit -m "README.md commit"
[...] README.md commit
1 file changed, 2 insertions(+)
create mode 100644 README.md
$
$ git status
[...]
nothing to commit, working tree clean
$
如果需要,可以将当前工作目录中的所有脚本同时添加到暂存区(索引)。只需使用 git
add .命令即可。注意,该命令结尾有个点号(.)! 这个点号相当于一个通配符,告诉 Git 把工作目录中的所有文件都加入暂存区。但是,如果不想把某些文件添加到暂存区,则可以在工作目录中创建一个.gitignore 文件,将不希望加入暂存区的文件或目录名写入该文件。这样, git add .命令就会忽略这些文件或目录,只把其他的文件或目录加入暂存区。
暂存区的索引文件是.git/index。如果对该文件使用 file 命令,则其类型会显示为 Git index。Git 会使用此文件跟踪变更:
$ file .git/index
.git/index: Git index, version 2, 1 entries
$
如果这是一个新的脚本项目,那么在注册过远程仓库账户后,需要创建一个称为 Markdown file 的特殊文件,其内容会显示在远程仓库的 Web 页面上,描述该仓库的相关信息。该文件使用 Markdown 语言编写。你需要将文件命名为 README.md。
可以随时查看 Git 日志,但最好在将脚本项目推送到远程存储库之前做这件事。每次提交都有一个对应的哈希值作为标识,这个值也会出现在日志中。此外,请注意各种注释以及日期和作者信息。
$ git log
commit 898330bd0b01e0b6eee507c5eeb3c72f9544f506[...]
Author: Christine Bresnahan
Date: Mon Aug 24 15:58:52 2020 -0400
README.md commit
commit 3b484638bc6e391d0a1b816946cba8c5f4bbc8e6
Author: Christine Bresnahan
Date: Mon Aug 24 15:46:56 2020 -0400
Initial Commit
$
在向远程仓库推送项目之前,需要先在系统中配置远程仓库地址。在使用 Git 服务提供商 (比如 GitHub)设置远程仓库时,它会向你提供此地址。
可以使用 git remote add origin URL 命令来添加地址, 其中 URL 就是远程仓库地址:
$ git remote add origin https://github.com/C-Bresnahan/MWGuard.git
$
$ git remote -v
origin https://github.com/C-Bresnahan/MWGuard.git (fetch)
origin https://github.com/C-Bresnahan/MWGuard.git (push)
$
配置好远程仓库地址之后,就可以向其推送脚本项目了。但在此之前,为简单起见,我们打算使用 git branch 命令把主分支重命名为main:
$ git branch -m main
$
$ git branch --show-current
main
$
将脚本复制到远程仓库。这需要在 push 命令中加入-u origin 选项来指定仓库位置和当前使用的分支名 main:
$ git remote add origin https://github.com/C-Bresnahan/MWGuard.git
$
$ git push -u origin main
Username for 'https://github.com ': C-Bresnahan
Password for 'https://C-Bresnahan@github.com ':
Enumerating objects: 6, done.
Counting objects: 100% (6/6), done.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (6/6), 604 bytes | 60.00 KiB/s, done.
Total 6 (delta 0), reused 0 (delta 0)
To https://github.com/C-Bresnahan/MWGuard.git
* [new branch] main -> main
Branch 'main' set up to track remote branch 'main' from 'origin'.
$
远程仓库真正的美妙之处在于, Linux 管理团队中参与此项目的任何人都可以使用 git pull 命令从中拉取最新版本的脚本。
$ git remote add origin https://github.com/C-Bresnahan/MWGuard.git
$
$ git pull origin main
remote: Enumerating objects: 6, done.
remote: Counting objects: 100% (6/6), done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 6 (delta 0), reused 6 (delta 0), pack-reused 0
Unpacking objects: 100% (6/6), 584 bytes | 58.00 KiB/s, done.
From https://github.com/C-Bresnahan/MWGuard
* branch
* [new branch]
$
如果未参与该项目的人想得到脚本的最新版本, 那么当他们尝试使用 git remote add origin 命令时, 会收到类似于 fatal: not a git repository 的错误消息。对这些人而言, 最好先克隆该项目。
开发团队的新成员可以使用 git clone 命令将整个脚本项目从远程仓库复制到自己的本地 系统:
$ git clone https://github.com/C-Bresnahan/MWGuard.git
Cloning into 'MWGuard'...
remote: Enumerating objects: 6, done.
remote: Counting objects: 100% (6/6), done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 6 (delta 0), reused 6 (delta 0), pack-reused 0
Unpacking objects: 100% (6/6), 584 bytes | 58.00 KiB/s, done.
$
$ ls
MWGuard
$
$ cd MWGuard/
$
$ ls -a
. .. .git MyGitExampleScript.sh README.md
$
$ git log
commit [...](HEAD -> main, origin/main, origin/HEAD)
Author: Christine Bresnahan
Date: Mon Aug 24 15:58:52 2020 -0400
README.md commit
commit 3b484638bc6e391d0a1b816946cba8c5f4bbc8e6
Author: Christine Bresnahan
Date: Mon Aug 24 15:46:56 2020 -0400
Initial Commit
$
命令 | 描述 |
---|---|
& | 在后台启动作业 |
((x)) | 执行数学表达式 x |
. | 在当前 shell 中读取并执行指定文件中的命令 |
: | 什么都不做,始终成功退出 |
[ t ] | 对条件表达式 t 进行求值 |
[[ e ]] | 对条件表达式 e 进行求值 |
alias | 为指定命令定义别名 |
bg | 将当前作业置于后台运行 |
bind | 将组合键绑定到 readline 函数或宏 |
Break | 退出 for、while、select 或 until 循环 |
builtin | 执行指定的 shell 内建命令 |
caller | 返回活动子函数调用的上下文 |
case | 根据模式有选择地执行命令 |
cd | 将当前目录切换为指定的目录 |
command | 执行指定的命令,不进行正常的 shell 查找(也就是说,绕过同名的别名或函数) |
compgen | 为指定单词生成可能的补全匹配 |
complete | 显示指定的单词是如何补全的 |
compopt | 修改指定单词的补全选项 |
continue | 继续执行 for、while、select 或 until 循环的下一次迭代 |
coproc | 在后台生成子 shell 并执行指定的命令 |
declare | 声明变量或变量类型 |
dirs | 显示当前已保存的目录列表 |
disown | 从进程作业表中删除指定的作业 |
echo | 将指定字符串输出到 STDOUT |
enable | 启用或禁用指定的内建 shell 命令 |
eval | 将指定的参数拼接成一个命令, 然后执行该命令 |
exec | 用指定命令替换 shell 进程 |
exit | 强制 shell 以指定的退出状态码退出 |
export | 设置可用于子 shell 进程的变量 |
false | 将结果设置为 false 状态 |
fc | 从历史记录列表(history list)中选择一组命令 |
fg | 将作业恢复至前台 |
for | 对列表中的每一项执行指定的命令 |
function | 定义一个 shell 脚本函数 |
getopts | 解析指定的位置参数 |
hash | 查找并记住指定命令的完整路径名 |
help | 显示 bash 内建命令的帮助页面 |
history | 显示命令历史记录 |
if | 根据条件表达式执行命令 |
jobs | 列出活动作业 |
kill | 向指定的进程 ID(PID )发送系统信号 |
let | 计算数学表达式 |
local | 在函数中创建局部变量 |
logout | 退出已登录的 shell |
mapfile | 从 STDIN 中读取输入并将其放入索引数组(每个数组元素包含一行) popd |
printf | 使用格式化字符串显示文本 |
pushd | 向目录栈压入一个目录 |
pwd | 显示当前工作目录的完整路径名 |
read | 从 STDIN 读取一行数据并将其中的每个单词赋给指定变量 |
readarray | 从 STDIN 读取数据行并将其放入索引数组(一个数组元素对应一行) |
readonly | 从 STDIN 读取一行数据并将其赋给一个不可修改的变量 |
return | 使函数以某个值退出,该值可由调用脚本(calling script)提取 |
select | 显示带编号的单词列表, 允许用户进行选择 |
set | 设置并显示环境变量的值和 shell 属性 |
shift | 将位置参数依次向前移动一个位置 |
shopt | 打开/关闭 shell 选项 |
source | 在当前 shell 中读取并执行指定文件中的命令 |
suspend | 暂停 shell,直至收到 SIGCONT 信号 |
test | 根据指定条件返回退出状态码 0 或 1 |
time | 显示执行指定命令所累计的真实时间(real time)、用户时间和系统时间 |
times | 显示累计的用户时间和系统时间 |
trap | 如果接收到特定的系统信号,就执行指定命令 |
true | 返回为 0 的退出状态码 |
type | 显示指定的单词作为命令名时, 如何被 shell 解释(也就是显示指定名称是外部命令、内建命令、别名、 shell 关键字或shell 函数) |
typeset | 声明变量或变量类型 |
ulimit | 为系统用户设置指定的资源上限 |
umask | 为新建的文件和目录设置默认权限 |
unalias | 删除指定的别名 |
unset | 删除指定的环境变量或 shell 属性 |
until | 执行指定的命令,直到条件语句返回 true |
wait | 等待指定的进程结束,返回退出状态码 |
while | 当条件语句返回 true 时,执行指定的命令 |
{ c; } | 在当前 shell 中指定一组命令 |
bash shell 外部命令
命令 | 描述 |
---|---|
at | 在未来的特定时间执行指定的脚本或命令 |
atq | 显示 at 命令队列中的作业 |
atrm | 从 at 命令队列中删除指定的作业 |
bash | 执行来自标准输入或指定文件中的命令, 或是启动一个子 shell |
bc | 使用 bc 的专用语言执行算术运算 |
bzip2 | 采用 Burrows-Wheeler 块排序文本压缩算法和霍夫曼编码进行压缩 |
cat | 列出指定文件的内容 |
chage | 修改指定系统用户账户的密码过期日期 |
chfn | 修改指定用户账户的备注信息 |
chgrp | 修改指定文件或目录的属组 |
chmod | 修改指定文件或目录的权限 |
chown | 修改指定文件或目录的属主 |
chpasswd | 读取包含用户名/密码的文件并更新相应用户的密码 |
chsh | 修改指定用户账户的默认 shell |
clear | 清空终端仿真器或虚拟控制台终端中的文字 |
compress | 最初的 Unix 文件压缩工具 |
cp | 将指定文件复制到另一个位置 |
crontab | 启动用户的 cron 表文件对应的编辑器(如果允许的话) |
cut | 打印文件中指定的部分 |
date | 以各种格式显示日期 |
df | 显示所有已挂载设备的当前磁盘使用情况 |
dialog | 在文本终端环境中创建窗口对话框 |
du | 显示指定目录的磁盘使用情况 |
emacs | 调用 Emacs 文本编辑器 |
env | 在修改过的环境中执行指定命令或显示所有的环境变量 |
exit | 终止当前进程 |
expr | 执行指定的算术表达式 |
fdisk | 维护或创建指定磁盘的分区表 |
file | 查看指定文件的文件类型 |
find | 查找文件 |
free | 查看系统可用的和已用的内存 |
fsck | 检查并根据需要修复指定的文件系统 |
gawk | 调用 gawk 编辑器 |
Grep | 在文件中查找指定模式的字符串 |
gedit | 调用 GNOME 桌面编辑器 |
getopt | 解析命令选项(包括长格式选项) |
gdialog | 创建 GNOME Shell 窗口对话框 |
groups | 显示指定用户的组成员关系 |
groupadd | 创建新的用户组 |
groupmod | 修改已有的用户组 |
gunzip | 出自 GNU 项目的文件解压缩工具,采用 Lempel-Ziv 压缩算法 |
gzcat | 出自 GNU 项目的压缩文件内容显示工具, 采用 Lempel-Ziv 压缩算法 |
gzip | 出自 GNU 项目的文件压缩工具, 采用 Lempel-Ziv 压缩算法 |
head | 显示指定文件的开头部分 |
kdialog | 创建 KDE 窗口对话框 |
killall | 根据进程名向运行中的进程发送系统信号 |
kwrite | 调用 KWrite 文本编辑器 |
less | 查看文件内容的高级命令 |
link | 使用别名创建文件链接 |
ln | 创建指定文件的符号链接或硬链接 |
ls | 列出目录内容或文件信息 |
lvcreate | 创建 LVM 卷 |
lvdisplay | 显示 LVM 卷 |
lvextend | 增加 LVM 卷的大小 |
lvreduce | 减少 LVM 卷的大小 |
mandb | 创建能够使用手册页关键字进行搜索的数据库 |
man | 显示指定命令或话题的手册页 |
mkdir | 创建指定目录 |
mkfs | 使用指定文件系统格式化分区 |
mktemp | 创建临时文件或目录 |
more | 显示指定文件的内容,每显示一屏数据后就暂停 |
mount | 显示或挂载磁盘设备到虚拟文件系统中 |
mv | 重命名文件或目录 |
nano | 调用 nano 文本编辑器 |
nice | 在系统中用指定的优先级运行命令 |
nohup | 执行指定的命令,同时忽略 SIGHUP 信号 |
passwd | 修改用户的账户密码 |
printenv | 显示指定环境变量或所有的环境变量的值 |
ps | 显示系统中运行进程的信息 |
pvcreate | 创建物理 LVM 卷 |
pvdisplay | 显示物理 LVM 卷 |
Pwd | 显示当前工作目录 |
renice | 修改系统中运行进程的优先级 |
rm | 删除指定文件或目录 |
rmdir | 删除指定的空目录 |
sed | 调用流编辑器 sed |
setterm | 修改终端设置 |
sleep | 在指定的一段时间内暂停 bash shell 操作 |
sort | 根据指定的顺序对文件内容进行排序 |
stat | 显示指定文件的相关信息 |
sudo | 以 root 用户账户身份运行应用程序 |
tail | 显示指定文件的末尾部分 |
tar | 将数据和目录归档到单个文件中 |
tee | 将信息发送到 STDOUT 和 STDIN |
top | 显示活动进程以及重要的系统统计数据 |
touch | 新建一个空文件或更新已有文件的时间戳 |
umount | 从虚拟文件系统中卸载磁盘设备 |
uptime | 显示系统已经运行了多久 |
useradd | 新建用户账户 |
userdel | 删除用户账户 |
usermod | 修改用户账户 |
vgchange | 激活或停用 LVM 卷组 |
vgcreate | 创建 LVM 卷组 |
vgdisplay | 显示 LVM 卷组 |
vgextend | 增加 LVM 卷组大小 |
vgreduce | 减少 LVM 卷组大小 |
vgremove | 删除 LVM 卷组 |
vi | 调用 vi 文本编辑器 |
vim | 调用 vim 文本编辑器 |
vmstat | 生成一份详尽的系统内存和 CPU 使用情况的报告 |
wc | 显示文本文件统计情况 |
whereis | 显示指定命令的相关文件,包括二进制文件、源代码文件以及手册页 |
which | 查找可执行文件的位置 |
who | 显示当前系统中的登录用户 |
whoami | 显示当前用户的用户名 |
xargs | 从 STDIN 中获取数据项, 构建并执行命令 |
xterm | 调用 xterm 终端仿真器 |
zenity | 创建 GNOME Shell 窗口小部件 |
zip | Windows PKZIP 程序的 Unix 版本 |
bash shell 环境变量
命令 | 描述 |
---|---|
* | 包含所有命令行参数(以单个文本值的形式) |
@ | 包含所有命令行参数(以多个文本值的形式) |
# | 命令行参数数目 |
? | 最近使用的前台进程的退出状态码 |
- | 当前命令行选项标记 |
$ | 当前 shell 的进程 ID(PID ) |
! | 最近执行的后台进程的 PID |
0 | 命令行中使用的命令名 |
_ | shell 的绝对路径名 |
BASH | 用来调用 shell 的完整路径名 |
BASHOPTS | 已启用的 shell 选项(以冒号分隔形式显示) |
BASHPID | 当前 bash shell 的 PID |
BASH_ALIASES | 数组变量,包含当前所用的别名 |
BASH_ARGC | 当前函数的参数数量 |
BASH_ARGV | 数组变量,包含所有的命令行参数 |
BASH_CMDS | 数组变量,包含命令的内部哈希表 |
BASH_COMMAND | 当前正在运行的命令名 |
BASH_ENV | 如果设置的话, 每个 bash 脚本都会尝试在运行前执行由该变量定义的启动文件 |
BASH_EXECUTION_STRING | 在-c 命令行选项中指定的命令 |
BASH_LINENO | 数组变量,包含脚本中每个命令的行号 |
BASH_REMATCH | 数组变量,包含正则表达式所匹配的文本(索引为 0 的元素是整个正则表达式所匹配的部分。索引为 n 的元素是第 n 个带有圆括号的子正则表达式所匹配的部分) |
BASH_SOURCE | 数组变量,包含 shell 中已定义函数所在源文件名 |
BASH_SUBSHELL | 当前 shell 生成的子 shell 数目 |
BASH_VERSINFO | 数组变量,包含当前 bash shell 实例的主版本号和次版本号 |
BASH_VERSION | 当前 bash shell 实例的版本号 |
BASH_XTRACEFD | 如果设置为有效的文件描述符整数,则所产生跟踪信息会与诊断和错误消息分开。文件 描述符必须事先执行 set -x |
BROWSER | 首选 Web 浏览器的绝对路径名 |
COLUMNS | 当前 bash shell 实例所用的终端宽度 |
COMP_CWORD | 变量 COMP_WORDS 的索引值, COMP_WORDS 包含当前光标所在的位置 |
COMP_KEY | 调用补全功能的按键 |
COMP_LINE | 当前命令行 |
COMP_POINT | 当前光标位置相对于当前命令起始处的索引 |
COMP_TYPE | 补全类型对应的整数值 |
COMP_WORDBREAKS | 在进行单词补全时作为单词分隔符的一组字符 |
COMP_WORDS | 数组变量,包含当前命令行上的所有单词 |
COMPREPLY | 数组变量,包含可能的补全结果 |
COPROC | 数组变量,包含用于匿名协程 I/O 的文件描述符 |
DBUS_SESSION_BUS_ADDRESS | 当前登录会话的 D-Bus 地址,用于提供连接映射 |
DE | 当前登录 shell 的桌面环境 |
DESKTOP_SESSION | 在 LXDE 环境中,包含当前登录 shell 的桌面环境 |
DIRSTACK | 数组变量,包含目录栈当前内容 |
DISPLAY | 图形应用程序映射,用于显示图形用户界面的位置 |
EDITOR | 定义部分 shell 命令使用的默认编辑器 |
EMACS | 如果设置的话, shell 会认为其使用的是 Emacs shell 缓冲区,同时禁止行编辑功能 |
ENV | 当 shell 以 POSIX模式调用时,每个 bash 脚本在运行之前都会执行由该环境变量所定义的启动文件 |
EUID | 当前用户的有效用户 ID (数字形式) |
FCEDIT | fc 命令使用的默认编辑器 |
FIGNORE | 以冒号分隔的后缀名列表,在文件名补全时会被忽略 |
FUNCNAME | 当前执行的 shell 函数的名称 |
FUNCNEST | 嵌套函数的最高级别 |
GLOBIGNORE | 以冒号分隔的模式列表, 文件名扩展时会将其忽略 |
GROUPS | 数组变量,包含当前用户属组 |
histchars | 控制历史记录扩展,最多可有 3 个字符 |
HISTCMD | 当前命令在历史记录中的编号 |
HISTCONTROL | 控制哪些命令会被保存在历史记录列表中 |
HISTFILE | 保存 shell 历史记录列表的文件名(默认是~/.bash_history) |
HISTFILESIZE | 历史记录文件(history file)能保存的最大命令数量 |
HISTIGNORE | 以冒号分隔的模式列表, 用来决定哪些命令不会被保存在历史文件中 |
HISTSIZE | 能写入历史记录列表(history list)的最大命令数量 |
HISTTIMEFORMAT | 如果设置的话, 该变量决定了历史文件条目时间戳所使用的格式字符串 |
HOME | 当前登录会话的主目录名 |
HOSTALIASES | 文件名, 某些 shell 命令要用到的各种主机名别名都保存在该文件中 |
HOSTFILE | shell 在补全主机名时要读取的文件名 |
HOSTNAME | 当前主机名 |
HOSTTYPE | 当前运行 bash shell 的机器 |
IFS | 在分割单词时作为分隔符使用的一系列字符 |
IGNOREEOF | shell 在退出前必须收到的一系列 EOF 字符的数量。如果未设置,则默认是 1 |
INFODIR | info 命令的搜索目录列表(以冒号分隔) |
INPUTRC | readline 初始化的文件名(默认是~/.inputrc) |
INVOCATION_ID | systemd 用于标识登录 shell 和其他单元的 128 位(128-bit)随机标识符 |
JOURNAL_STREAM | 文件描述符的设备和 inode 编号(十进制格式) 列表(以冒号分隔)。仅当 STDOUT 或 STDERR 连接到日志系统时才设置 |
LANG | shell 的语言环境种类(locale category) |
LC_ALL | 定义语言环境种类,能够覆盖 LANG 变量 |
LC_ADDRESS | 确定地址信息的显示方式 |
LC_COLLATE | 设置字符串排序时采用的排序规则 |
LC_CTYPE | 决定如何解释出现在文件名扩展和模式匹配中的字符 |
LC_IDENTIFICATION | 包含语言环境的元数据信息 |
LC_MEASUREMENT | 设置用于测量单位的语言环境 |
LC_MESSAGES | 决定在解释前面带有$的双引号字符串时采用的语言环境设置 |
LC_MONETARY | 定义货币数值的格式 |
LC_NAME | 设置名称的格式 |
LC_NUMERIC | 决定格式化数字时采用的语言环境设置 |
LC_PAPER | 设置用于纸张标准和格式的语言环境 |
LC_TELEPHONE | 设置电话号码的结构 |
LD_LIBRARY_PATH | 以冒号分隔的目录列表, 其中的目录会先于标准库目录被搜索 |
LC_TIME | 决定格式化日期和时间时采用的语言环境设置 |
LINENO | 当前正在执行的脚本语句的行号 |
LINES | 定义了终端上可见的行数 |
LOGNAME | 当前登录会话的用户名 |
LS_COLORS | 定义用于显示文件名的颜色 |
MACHTYPE | 用“CPU–公司–系统”(CPU-company-system)格式定义的系统类型 |
如果设置的话,定义当前登录会话的邮件文件会被一些邮件程序间歇地搜索,以查找新邮件 | |
MAILCHECK | shell 应该多久检查一次新邮件(以秒为单位,默认为 60 秒) |
MAILPATH | 以冒号分隔的邮件文件名列表,一些邮件程序会间歇性地在其中搜索新邮件 |
MANPATH | 以冒号分隔的手册页目录列表, 由 man 命令搜索 |
MAPFILE | 数组变量,当未指定数组变量作为参数时,其中保存了 mapfile 所读入的文本 |
OLDPWD | shell 先前使用的工作目录 |
OPTARG | 包含选项所需的参数值, 由 getopts 命令设置 |
OPTERR | 如果设置为 1 ,则 bash shell 会显示 getopts 命令产生的错误 |
OPTIND | getopts 命令要处理的下一个参数的索引 |
OSTYPE | 定义了 shell 所在的操作系统 |
PAGER | 设置某些 shell 命令在查看文件时使用的分页实用工具 |
PATH | 以冒号分隔的目录列表, shell 会在其中搜索外部命令 |
PIPESTATUS | 数组变量,包含前台进程的退出状态 |
POSIXLY_CORRECT | 如果设置的话, bash 会以 POSIX 模式启动 |
PPID | bash shell 父进程的 PID |
PROMPT_COMMAND | 如果设置的话, 在显示命令行主提示符之前执行该命令 |
PROMPT_DIRTRIM | 用来定义使用提示符字符串\w 或\W 转义时显示的拖尾(trailing)目录名的数量(使用一组英文句点替换被删除的目录名) |
PS0 | 如果设置的话, 该变量会指定在输入命令之后、执行命令之前,由交互式 shell 显示的内容 |
PS1 | 主命令行提示符 |
PS2 | 次命令行提示符 |
PS3 | select 命令的提示符 |
PS4 | 在命令行之前显示的提示符(如果使用了 bash 的-x 选项的话) |
PWD | 当前工作目录 |
RANDOM | 返回一个介于 0 ~ 32 767 的随机数(对该变量的赋值可作为随机数生成器的种子) |
READLINE_LINE | 当使用 bind –x 命令时, 保存 Readline 缓冲区的内容 |
READLINE_POINT | 当使用 bind –x 命令时, 指明了 Readline 缓冲区内容插入点的当前位置 |
REPLY | read 命令的默认变量 |
SECONDS | 自 shell 启动到现在的秒数(对其赋值会重置计数器) |
SHELL | bash shell 的完整路径 |
SHELLOPTS | 已启用的 bash shell 选项(以冒号分隔) |
SHLVL | shell 的层级;每启动一个新的 bash shell,该值增加 1 |
TERM | 登录会话当前使用的终端类型, 相关信息由该变量所指向的文件提供 |
TERMCAP | 登录会话当前使用的终端类型, 相关信息由该变量提供 |
TIMEFORMAT | 指定了 shell 的时间显示格式 |
TMOUT | select 命令和 read 命令在无输入的情况下等待多久(以秒为单位。默认值为 0,表示一直等待) |
TMPDIR | 目录名, 保存 bash shell 创建的临时文件 |
TZ | 如果设置的话, 用于指定系统的时区 |
TZDIR | 定义时区文件所在的目录 |
UID | 当前用户的真实用户 ID (数字形式) |
USER | 当前登录会话的用户名 |
VISUAL | 如果设置的话, 用于定义某些 shell 命令默认使用的全屏编辑器 |
sed 命令的格式如下:
sed options script file
options 允许定制 sed 命令的行为,sed 命令选项如下表:
选项 | 描述 |
---|---|
-e script | 在处理输入时, 加入 script 中指定的命令 |
-f file | 在处理输入时, 加入文件file 中包含的命令 |
-n | 不再为每条命令产生输出,而是等待打印(p)命令 |
script 指定了应用于数据流的单条命令。如果用到的命令不止一条,则要么使用-e 选项在命令行上指定,要么使用-f 选项在一个单独的文件中指定。
s/pattern/replacement/flags
[address]command
$ sed '2,3s/dog/cat/' data1
/pattern/command
$ sed '/rich/s/bash/csh/' /etc/passwd
address {
command1
command2
command3 }
$ sed '2{
> s/fox/elephant/
> s/dog/cat/
> }' data1
要么通过行号指定地址:
$ sed '3d' data1
要么通过行区间指定地址:
$ sed '2,3d' data1
$ sed '/number 1/d' data1
sed ' [address]command\
new line '
$ sed '3c\
> This is a changed line of text.' data1
[address]y/inchars/outchars/
$ sed -n '/number 3/p' data1
This is line number 3.
$
[address]w filename
[address]r filename
$ sed '3r data' data1
gawk options program file
选项 | 描述 |
---|---|
-F fs | 指定用于划分行中各个数据字段的字段分隔符 |
-f file | 指定要从哪个文件中读取脚本 |
-v var=value | 定义 gawk 脚本中要使用的变量及其默认值 |
-mf N | 指定数据文件中的最大字段数 |
-mr N | 指定数据文件中的最大记录数 |
-W keyword | 指定 gawk 的兼容模式或警告等级。使用 help 选项列出所有可用的关键字 |
$ gawk '{print $1}'
$ echo "My name is Rich" | gawk '{$4="Dave"; print $0}'
My name is Dave
$
$ cat script1
{ print $5 "'s userid is " $1 }
$ gawk -F: -f script1 /etc/passwd
$ gawk 'BEGIN {print "This is a test report"}'
This is a test report
$
$ gawk 'BEGIN {print "Hello World!"} {print $0} END {print
"byebye"}' data1
Hello World!
This is a test
This is a test
This is another test.
This is another test.
byebye
$
gawk 脚本使用内建变量来引用特定的数据信息。
gawk 脚本会将数据定义为记录和数据字段。记录是一行数据(默认以换行符分隔),而数据字段则是行中独立的数据元素(默认以空白字符分隔,比如空格或制表符)。
gawk 脚本使用数据字段来引用每条记录中的数据元素。
gawk 数据字段和记录变量:
变量 | 描述 |
---|---|
$0 | 整条记录 |
$1 | 记录中的第一个数据字段 |
$2 | 记录中的第二个数据字段 |
$n | 记录中的第 n 个数据字段 |
FIELDWIDTHS | 由空格分隔的数字列表,定义了每个数据字段的具体宽度 |
FS | 输入字段分隔符 |
RS | 输入记录分隔符 |
OFS | 输出字段分隔符 |
ORS | 输出记录分隔符 |
更多的 gawk 内建变量:
变量 | 描述 |
---|---|
ARGC | 当前命令行参数的个数 |
ARGIND | 当前文件在 ARGV 数组中的索引 |
ARGV | 包含命令行参数的数组 |
CONVFMT | 数字的转换格式(参见 printf 语句),默认值为%.6g |
ENVIRON | 由当前 shell 环境变量及其值组成的关联数组 |
ERRNO | 当读取或关闭输入文件发生错误时的系统错误号 |
FILENAME | 作为 gawk 输入的数据文件的文件名 |
FNR | 当前数据文件中的记录数 |
IGNORECASE | 如果设置成非 0 值,则 gawk 会忽略所有字符串函数(包括正则表达式)中的字符大小写 |
NF | 数据文件中的数据字段总数 |
NR | 已处理的输入记录数 |
OFMT | 数字的输出格式,默认值为%.6g |
RLENGTH | 由 match 函数所匹配的子串的长度 |
RSTART | 由 match 函数所匹配的子串的起始位置 |
在 gawk 脚本中给变量赋值需要使用赋值语句:
$ gawk '
> BEGIN{
> testing="This is a test"
> print testing
> }'
This is a test
$
也可以在 gawk 命令行上给变量赋值。这允许在正常脚本之外即时设置或修改变量值。下面的例子使用命令行变量显示文件中特定数据字段:
$ cat script1
BEGIN{FS=","}
{print $n}
$ gawk -f script1 n=2 data1
$ gawk -f script1 n=3 data1
$ gawk 'BEGIN{FS=","} /test/{print $1}' data1
This is a test
$
$1 ~ /^data/
$ gawk -F: '$4 == 0{print $1}' /etc/passwd
if-then-else 语句:
if (condition) statement1; else statement2
while 语句:
while (condition)
{
statements
}
do-while 语句:
do {
statements
} while (condition)
for 语句:
for(variable assignment; condition; iteration process)