Shell 脚本实现scp 自动化交互

ttgo2 发表了文章 • 0 个评论 • 141 次浏览 • 2018-08-06 18:30 • 来自相关话题

Linux  shell 命令scp 可以实现远程拷贝文件,但是需要人工进行交互,无法使用shell 脚本进行自动化的方式来实现,如果能自动化实现呢? 今天我们来解决这个问题。
 
1、 expect是一个自动交互功能的工具。expect是开了一个子进程,通过spawn来执行shell脚本,监测到脚本的返回结果,通过expect判断要进行的交互输入内容(send),以chat的方式解决了交互的问题。
 





2、默认情况下centos 没有安装,可以通过yum 来进行安装,具体命令为:yum install expect  截图如下:






3、 验证一下是否安装expect成功,截图如下






4、举例来说明expect的格式命令和具体的方法
 
step1: 创建一个后缀名为.exp的文件,scp.exp ,具体代码如下
 #!/usr/bin/expect -f
set timeout 10

set host [lindex $argv 0]
set username [lindex $argv 1]
set password [lindex $argv 2]
set src_file [lindex $argv 3]
set dest_file [lindex $argv 4]

#这里的 set 使用来定义位置变量的,执行脚本的时候传入位置变量spawn scp -r $src_file $username@$host:/tmp/$dest_file
expect {
"(yes/no)?" {
send "yes\n"
expect "*assword:" { send "$password\n" }
}
"*assword:" {
send "$password\n"
}
}


expect "100%"
expect eof:


5 执行过程,
 
step1: 脚本的赋值执行权限,chmod +x scp.exp
 
step2: ./scp.exp 192.168.3.129 root 123456 1.txt 1.txt
 





 
  查看全部
Linux  shell 命令scp 可以实现远程拷贝文件,但是需要人工进行交互,无法使用shell 脚本进行自动化的方式来实现,如果能自动化实现呢? 今天我们来解决这个问题。
 
1、 expect是一个自动交互功能的工具。expect是开了一个子进程,通过spawn来执行shell脚本,监测到脚本的返回结果,通过expect判断要进行的交互输入内容(send),以chat的方式解决了交互的问题。
 
C1CC1CF7-B617-45dd-BDB2-A55EEB216A35.png


2、默认情况下centos 没有安装,可以通过yum 来进行安装,具体命令为:yum install expect  截图如下:

QQ截图20180808163745.png


3、 验证一下是否安装expect成功,截图如下

QQ截图20180808164710.png


4、举例来说明expect的格式命令和具体的方法
 
step1: 创建一个后缀名为.exp的文件,scp.exp ,具体代码如下
 
#!/usr/bin/expect -f
set timeout 10

set host [lindex $argv 0]
set username [lindex $argv 1]
set password [lindex $argv 2]
set src_file [lindex $argv 3]
set dest_file [lindex $argv 4]

#这里的 set 使用来定义位置变量的,执行脚本的时候传入位置变量
spawn scp -r $src_file $username@$host:/tmp/$dest_file
expect {
"(yes/no)?" {
send "yes\n"
expect "*assword:" { send "$password\n" }
}
"*assword:" {
send "$password\n"
}
}


expect "100%"
expect eof:


5 执行过程,
 
step1: 脚本的赋值执行权限,chmod +x scp.exp
 
step2: ./scp.exp 192.168.3.129 root 123456 1.txt 1.txt
 

QQ截图20180808170100.png

 
 

【Kali Linux网络扫描秘籍系列】Bash脚本+ARPing 实现自动化IP扫描

kakaxi 发表了文章 • 0 个评论 • 175 次浏览 • 2018-05-29 11:27 • 来自相关话题

ARPing简介:
ARPing 是一个命令行网络工具,具有类似于常用的 ping 工具的功能。 此工具可通过提供该 IP 地址作为参数,来识别活动主机是否位于给定 IP 的本地网络上。 这个秘籍将讨论如何使用 ARPing 扫描网络上的活动主机。
 
准备
要使用 ARPing 执行 ARP 发现,你需要在 LAN 上至少拥有一个响应 ARP 请求的系统。本测试在Kali 2.0上进行
 
操作步骤
ARPing是一种工具,可用于发送 ARP 请求并标识主机是否活动和响应。 该工具仅通过将 IP 地址作为参数传递给它来使用:root@kali:~# arping -c 1 172.16.155.1
ARPING 172.16.155.1 from 172.16.155.150 eth0
Unicast reply from 172.16.155.1 [00:50:56:C0:00:08] 1.047ms
Sent 1 probes (1 broadcast(s))
Received 1 response(s)
root@kali:~#



在所提供的示例中,单个 ARP 请求被发送给广播地址,请求 172.16.155.1 IP地址的物理位置。 如输出所示,主机从 000:50:56:C0:00:08 MAC地址接收到单个应答。 此工具可以更有效地用于第二层上的发现,扫描是否使用 bash 脚本在多个主机上同时执行此操作。 为了测试 bash 中每个实例的响应,我们应该确定响应中包含的唯一字符串,它标识了活动主机,但不包括没有收到响应时的情况。要识别唯一字符串,应该对无响应的 IP 地址进行 ARPing 请求:root@kali:~# arping -c 1 172.16.155.100
ARPING 172.16.155.100 from 172.16.155.150 eth0
Sent 1 probes (1 broadcast(s))
Received 0 response(s)




通过分析来自成功和失败的不同 ARP 响应,你可能注意到,如果存在所提供的 IP地址的相关活动主机,并且它也在包含在 IP 地址的行内,则响应中存在来自字符串的唯一字节。 通过对此响应执行 grep ,我们可以提取每个响应主机的 IP 地址:root@kali:~# arping -c 1 172.16.155.1 | grep 'reply from'
Unicast reply from 172.16.155.1 [00:50:56:C0:00:08] 0.712ms



我们可以仅仅通过处理提供给 cut 函数的分隔符和字段值,从返回的字符串中轻松地提取 IP 地址:root@kali:~# arping -c 1 172.16.155.1 | grep 'reply from' |cut -d ' ' -f 4
172.16.155.1在识别如何从正面 ARPing 响应中提取 IP 在 bash 脚本中轻易将该任务传递给循环,并输出实时 IP 地址列表。 使用此技术的脚本的示例如下所示:root@kali:~# cat arping.sh 
#!/bin/bash
if [ $# -ne 1 ]; then
    echo "Usage - ./arping.sh [interface]"
    echo "Example - ./arping.sh eth0"
    echo "Example will perform an ARP scan of the local subnet to which eth0 is assigned"
    exit
fi

interface=$1
prefix=$(ifconfig $inerface | grep 'inet'| head -n 1| cut -d ' ' -f 10|cut -d '.' -f 1-3 ) #  由于输出的间隔符空格,因此我这边cut -d后面用的是空格,大家做的过程中,可以根据自己的情况变化

for addr in $(seq 1 254); do 
    arping -c 1 $prefix.$addr | grep 'reply from' |cut -d ' ' -f 4 &
done在提供的 bash 脚本中,第一行定义了 bash 解释器的位置。接下来的代码块执行测试,来确定是否提供了预期的参数。这通过评估提供的参数的数量是否不等于 1来确定。如果未提供预期参数,则输出脚本的用法,并且退出脚本。用法输出表明,脚本预期将本地接口名称作为参数。下一个代码块将提供的参数赋给 interface 变量。然后将接口值提供给 ifconfig ,然后使用输出提取网络前缀。例如,如果提供的接口的 IP 地址是 192.168.11.4 ,则前缀变量将赋为 192.168.11 。然后使用 for 循环遍历最后一个字节的值,来在本地 / 24 网络中生成每个可能的 IP 地址。对于每个可能的 IP 地址,执行单个 arping 命令。然后对每个请求的响应通过管道进行传递,然后使用 grep 来提取带有短语 bytes 的行。如前所述,这只会提取包含活动主机的 IP 地址的行。最后,使用一系列 cut 函数从此输出中提取 IP 地址。请注意,在 for 循环任务的末尾使用 & 符号,而不是分号。符号允许并行执行任务,而不是按顺序执行。这极大地减少了扫描 IP 范围所需的时间。
注意:给文件增加执行权限如下命令集:root@kali:~# chmod +x arping.sh
root@kali:~# ls -al arping.sh
-rwxr-xr-x 1 root root 552 May 28 23:18 arping.sh
root@kali:~#
 
看看下面的执行命令集:root@kali:~# ./arping.sh
Usage - ./arping.sh [interface]
Example - ./arping.sh eth0
Example will perform an ARP scan of the local subnet to which eth0 is assigned
root@kali:~# ./arping.sh eth0
root@kali:~# 172.16.155.1
172.16.155.2
172.16.155.254




可以轻易将脚本的输出重定向到文本文件,然后用于随后的分析。 可以使用尖括号重定向输出,后跟文本文件的名称。 一个例子如下:root@kali:~# ./arping.sh eth0 > output.txt
root@kali:~# ls output.txt
output.txt
root@kali:~# cat output.txt
172.16.155.1
172.16.155.2
172.16.155.254
root@kali:~#



一旦输出重定向到输出文件,你就可以使用 ls 命令验证文件是否已写入文件系统,或者可以使用 cat 命令查看文件的内容。 此脚本还可以修改为从输入文件读取,并仅验证此文件中列出的主机是否处于活动状态。 对于以下脚本,你需要拥有IP 地址列表的输入文件。 为此,我们可以使用与上一个秘籍中讨论的 Scapy 脚本所使用的相同的输入文件:#!/bin/bash
if [ $# -ne 1 ]; then
echo "Usage - ./arping.sh [interface]"
echo "Example - ./arping.sh eth0"
echo "Example will perform an ARP scan of the local subnet to which eth0 is assigned"
exit
fi

file=$1

for addr in $(cat $file); do
arping -c 1 $addr | grep 'reply from' |cut -d ' ' -f 4 &
done




这个脚本和前一个脚本唯一的主要区别是,并没有提供一个接口名,而是在执行脚本时提供输入列表的文件名。 这个参数被传递给文件变量。 然后, for 循环用于循环遍历此文件中的每个值,来执行 ARPing 任务。 为了执行脚本,请使用句号和斜杠,后跟可执行脚本的名称:root@kali:~# ./arping.sh
Usage - ./arping.sh [interface]
Example - ./arping.sh eth0
Example will perform an ARP scan of the local subnet to which eth0 is assigned
root@kali:~# ./arp.sh output.txt
-bash: ./arp.sh: No such file or directory
root@kali:~#




 工作原理
 
ARPing 是一个工具,用于验证单个主机是否在线。 然而,它的简单用法的使我们很容易操作它在 bash 中按顺序扫描多个主机。 这是通过循环遍历一系列 IP 地址,然后将这些 IP 地址作为参数提供给工具来完成的。
  查看全部
ARPing简介:
ARPing 是一个命令行网络工具,具有类似于常用的 ping 工具的功能。 此工具可通过提供该 IP 地址作为参数,来识别活动主机是否位于给定 IP 的本地网络上。 这个秘籍将讨论如何使用 ARPing 扫描网络上的活动主机。
 
准备
要使用 ARPing 执行 ARP 发现,你需要在 LAN 上至少拥有一个响应 ARP 请求的系统。本测试在Kali 2.0上进行
 
操作步骤
ARPing是一种工具,可用于发送 ARP 请求并标识主机是否活动和响应。 该工具仅通过将 IP 地址作为参数传递给它来使用:
root@kali:~# arping -c 1 172.16.155.1
ARPING 172.16.155.1 from 172.16.155.150 eth0
Unicast reply from 172.16.155.1 [00:50:56:C0:00:08] 1.047ms
Sent 1 probes (1 broadcast(s))
Received 1 response(s)
root@kali:~#



在所提供的示例中,单个 ARP 请求被发送给广播地址,请求 172.16.155.1 IP地址的物理位置。 如输出所示,主机从 000:50:56:C0:00:08 MAC地址接收到单个应答。 此工具可以更有效地用于第二层上的发现,扫描是否使用 bash 脚本在多个主机上同时执行此操作。 为了测试 bash 中每个实例的响应,我们应该确定响应中包含的唯一字符串,它标识了活动主机,但不包括没有收到响应时的情况。要识别唯一字符串,应该对无响应的 IP 地址进行 ARPing 请求:
root@kali:~# arping -c 1 172.16.155.100
ARPING 172.16.155.100 from 172.16.155.150 eth0
Sent 1 probes (1 broadcast(s))
Received 0 response(s)




通过分析来自成功和失败的不同 ARP 响应,你可能注意到,如果存在所提供的 IP地址的相关活动主机,并且它也在包含在 IP 地址的行内,则响应中存在来自字符串的唯一字节。 通过对此响应执行 grep ,我们可以提取每个响应主机的 IP 地址:
root@kali:~# arping -c 1 172.16.155.1 | grep 'reply from' 
Unicast reply from 172.16.155.1 [00:50:56:C0:00:08] 0.712ms



我们可以仅仅通过处理提供给 cut 函数的分隔符和字段值,从返回的字符串中轻松地提取 IP 地址:
root@kali:~# arping -c 1 172.16.155.1 | grep 'reply from' |cut -d ' ' -f 4
172.16.155.1
在识别如何从正面 ARPing 响应中提取 IP 在 bash 脚本中轻易将该任务传递给循环,并输出实时 IP 地址列表。 使用此技术的脚本的示例如下所示:
root@kali:~# cat arping.sh 
#!/bin/bash
if [ $# -ne 1 ]; then
    echo "Usage - ./arping.sh [interface]"
    echo "Example - ./arping.sh eth0"
    echo "Example will perform an ARP scan of the local subnet to which eth0 is assigned"
    exit
fi

interface=$1
prefix=$(ifconfig $inerface | grep 'inet'| head -n 1| cut -d ' ' -f 10|cut -d '.' -f 1-3 ) #  由于输出的间隔符空格,因此我这边cut -d后面用的是空格,大家做的过程中,可以根据自己的情况变化

for addr in $(seq 1 254); do 
    arping -c 1 $prefix.$addr | grep 'reply from' |cut -d ' ' -f 4 &
done
在提供的 bash 脚本中,第一行定义了 bash 解释器的位置。接下来的代码块执行测试,来确定是否提供了预期的参数。这通过评估提供的参数的数量是否不等于 1来确定。如果未提供预期参数,则输出脚本的用法,并且退出脚本。用法输出表明,脚本预期将本地接口名称作为参数。下一个代码块将提供的参数赋给 interface 变量。然后将接口值提供给 ifconfig ,然后使用输出提取网络前缀。例如,如果提供的接口的 IP 地址是 192.168.11.4 ,则前缀变量将赋为 192.168.11 。然后使用 for 循环遍历最后一个字节的值,来在本地 / 24 网络中生成每个可能的 IP 地址。对于每个可能的 IP 地址,执行单个 arping 命令。然后对每个请求的响应通过管道进行传递,然后使用 grep 来提取带有短语 bytes 的行。如前所述,这只会提取包含活动主机的 IP 地址的行。最后,使用一系列 cut 函数从此输出中提取 IP 地址。请注意,在 for 循环任务的末尾使用 & 符号,而不是分号。符号允许并行执行任务,而不是按顺序执行。这极大地减少了扫描 IP 范围所需的时间。
注意:给文件增加执行权限如下命令集:
root@kali:~# chmod +x arping.sh
root@kali:~# ls -al arping.sh
-rwxr-xr-x 1 root root 552 May 28 23:18 arping.sh
root@kali:~#

 
看看下面的执行命令集:
root@kali:~# ./arping.sh
Usage - ./arping.sh [interface]
Example - ./arping.sh eth0
Example will perform an ARP scan of the local subnet to which eth0 is assigned
root@kali:~# ./arping.sh eth0
root@kali:~# 172.16.155.1
172.16.155.2
172.16.155.254




可以轻易将脚本的输出重定向到文本文件,然后用于随后的分析。 可以使用尖括号重定向输出,后跟文本文件的名称。 一个例子如下:
root@kali:~# ./arping.sh eth0 > output.txt
root@kali:~# ls output.txt
output.txt
root@kali:~# cat output.txt
172.16.155.1
172.16.155.2
172.16.155.254
root@kali:~#



一旦输出重定向到输出文件,你就可以使用 ls 命令验证文件是否已写入文件系统,或者可以使用 cat 命令查看文件的内容。 此脚本还可以修改为从输入文件读取,并仅验证此文件中列出的主机是否处于活动状态。 对于以下脚本,你需要拥有IP 地址列表的输入文件。 为此,我们可以使用与上一个秘籍中讨论的 Scapy 脚本所使用的相同的输入文件:
#!/bin/bash
if [ $# -ne 1 ]; then
echo "Usage - ./arping.sh [interface]"
echo "Example - ./arping.sh eth0"
echo "Example will perform an ARP scan of the local subnet to which eth0 is assigned"
exit
fi

file=$1

for addr in $(cat $file); do
arping -c 1 $addr | grep 'reply from' |cut -d ' ' -f 4 &
done




这个脚本和前一个脚本唯一的主要区别是,并没有提供一个接口名,而是在执行脚本时提供输入列表的文件名。 这个参数被传递给文件变量。 然后, for 循环用于循环遍历此文件中的每个值,来执行 ARPing 任务。 为了执行脚本,请使用句号和斜杠,后跟可执行脚本的名称:
root@kali:~# ./arping.sh 
Usage - ./arping.sh [interface]
Example - ./arping.sh eth0
Example will perform an ARP scan of the local subnet to which eth0 is assigned
root@kali:~# ./arp.sh output.txt
-bash: ./arp.sh: No such file or directory
root@kali:~#




 工作原理
 
ARPing 是一个工具,用于验证单个主机是否在线。 然而,它的简单用法的使我们很容易操作它在 bash 中按顺序扫描多个主机。 这是通过循环遍历一系列 IP 地址,然后将这些 IP 地址作为参数提供给工具来完成的。
 

详解 awk 工具的使用方法

wukong 发表了文章 • 4 个评论 • 355 次浏览 • 2017-05-26 08:19 • 来自相关话题

                                          详解 awk 工具的使用方法

详解 awk 工具的使用方法2017-05-22 程序员的那些事
来源:jarly
https://my.oschina.net/jarly/blog/898144
如有好文章投稿,请点击 → 这里了解详情

【伯乐在线转注】:awk 是一个强大的文本分析工具。它不仅是 Linux 中,也是任何环境中现有的功能最强大的数据处理引擎之一。相对于 grep 的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大。


当你第一次拿起双手在电脑上使用 awk 命令处理一个或者多个文件的时候,它会依次读取文件的每一行内容, 然后对其进行处理,awk 命令默认从 stdio 标准输入获取文件内容, awk 使用一对单引号来表示 一些可执行的脚本代码,在可执行脚本代码里面,使用一对花括号来表示一段可执行代码块,可以同时存在多个代码块。 awk 的每个花括号内同时又可以有多个指令,每一个指令用分号分隔,awk 其实就是一个脚本编程语言。说了这么多,你肯定还是一脸的懵逼。你猜对了,上面这些都是废话。先别急,客官请往下看……




awk 命令的基本格式

awk [options] 'program' file

options 这个表示一些可选的参数选项,反正就是你爱用不用,不用可以拉到。。。 program 这个表示 awk 的可执行脚本代码,这个是必须要有的。 file 这个表示 awk 需要处理的文件,注意是纯文本文件,不是你的 mp3,也不是 mp4 啥的。。

先来一个 awk 的使用例子热热身

$ awk '{print $0}' /etc/passwd

awk 命令的可执行脚本代码使用单引号括起来,紧接着里面是一对花括号,记住是 “花括号” 不是 “花姑娘”,然后花括号里面就是一些可执行的脚本代码段,当 awk 每读取一行之后,它会依次执行双引号里面的每个脚本代码段,在上面这个例子中, $0 表示当前行。当你执行了上面的命令之后,它会依次将 /etc/passwd 文件的每一行内容打印输出,你一定在想:这有个毛用,用 cat 命令也能搞定。没错!上面这个命令没个毛用,请往下看。

awk 自定义分隔符

awk 默认的分割符为空格和制表符,我们可以使用 -F 参数来指定分隔符

$ awk -F ':' '{print $1}' /etc/passwd

root

bin

daemon

adm

lp

sync

shutdown

halt

mail

operator

games

ftp

nobody

上面的命令将 /etc/passwd 文件中的每一行用冒号 : 分割成多个字段,然后用 print 将第 1 列字段的内容打印输出

如何在 awk 中同时指定多个分隔符

比如现在有这样一个文件 some.log 文件内容如下

Grape(100g)1980

raisins(500g)1990

plum(240g)1997

apricot(180g)2005

nectarine(200g)2008

现在我们想将上面的 some.log 文件中按照 “水果名称(重量)年份” 来进行分割

$ awk -F '[()]' '{print $1, $2, $3}' some.log

Grape 100g 1980

raisins 500g 1990

plum 240g 1997

apricot 180g 2005

nectarine 200g 2008

在 -F 参数中使用一对方括号来指定多个分隔符,awk 处理 some.log 文件时就会使用 “(” 和 “)” 来对文件的每一行进行分割。

awk 内置变量的使用

$0 这个表示文本处理时的当前行

$1 表示文本行被分隔后的第 1 个字段列

$2 表示文本行被分割后的第 2 个字段列

$3 表示文本行被分割后的第 3 个字段列

$n 表示文本行被分割后的第 n 个字段列

NR 表示文件中的行号,表示当前是第几行

NF 表示文件中的当前行列的个数,类似于 mysql 数据表里面每一条记录有多少个字段

FS 表示 awk 的输入分隔符,默认分隔符为空格和制表符,你可以对其进行自定义设置

OFS 表示 awk 的输出分隔符,默认为空格,你也可以对其进行自定义设置

FILENAME 表示当前文件的文件名称,如果同时处理多个文件,它也表示当前文件名称

比如我们有这么一个文本文件 fruit.txt 内容如下,我将用它来向你演示如何使用 awk 命令工具,顺便活跃一下此时尴尬的气氛。。

peach    100   Mar  1997   China

Lemon    150   Jan  1986   America

Pear     240   Mar  1990   Janpan

avocado  120   Feb  2008   china

我们来瞧一瞧下面这些简单到爆炸的例子,这个表示打印输出文件的每一整行的内容

$ awk '{print $0}' fruit.txt

peach    100   Mar  1997   China

Lemon    150   Jan  1986   America

Pear     240   Mar  1990   Janpan

avocado  120   Feb  2008   china

下面这个表示打印输出文件的每一行的第 1 列内容

$ awk '{print $1}' fruit.txt

peach

Lemon

Pear

avocado

下面面这个表示打印输出文件的每一行的第 1 列、第 2 列和第 3 列内容

$ awk '{print $1, $2, $3}' fruit.txt

peach 100 Mar

Lemon 150 Jan

Pear 240 Mar

avocado 120 Feb

其中加入的逗号表示插入输出分隔符,也就是默认的空格

文件的每一行的每一列的内容除了可以用 print 命令打印输出以外,还可以对其进行赋值

$ awk '{$2 = "***"; print $0}' fruit.txt

peach *** Mar 1997 China

Lemon *** Jan 1986 America

Pear *** Mar 1990 Janpan

avocado *** Feb 2008 china

上面的例子就是表示通过对 $2 变量进行重新赋值,来隐藏每一行的第 2 列内容,并且用星号 * 来代替其输出

在参数列表中加入一些字符串或者转义字符之类的东东

$ awk '{print $1 "\t" $2 "\t" $3}' fruit.txt

peach   100     Mar

Lemon   150     Jan

Pear    240     Mar

avocado 120     Feb

像上面这样,你可以在 print的参数列表中加入一些字符串或者转义字符之类的东东,让输出的内容格式更漂亮,但一定要记住要使用双引号。

awk 内置 NR 变量表示每一行的行号

$ awk '{print NR "\t" $0}' fruit.txt

1   peach    100   Mar  1997   China

2   Lemon    150   Jan  1986   America

3   Pear     240   Mar  1990   Janpan

4   avocado  120   Feb  2008   china

awk 内置 NF 变量表示每一行的列数

$ awk '{print NF "\t" $0}' fruit.txt

5   peach    100   Mar  1997   China

5   Lemon    150   Jan  1986   America

5   Pear     240   Mar  1990   Janpan

5   avocado  120   Feb  2008   china

awk 中 $NF 变量的使用

$ awk '{print $NF}' fruit.txt

China

America

Janpan

china

上面这个 $NF 就表示每一行的最后一列,因为 NF 表示一行的总列数,在这个文件里表示有 5 列,然后在其前面加上 $ 符号,就变成了 $5 ,表示第 5 列

$ awk '{print $(NF - 1)}' fruit.txt

1997

1986

1990

2008

上面 $(NF-1) 表示倒数第 2 列, $(NF-2) 表示倒数第 3 列,依次类推。

yahoo   100 4500

google  150 7500

apple   180 8000

twitter 120 5000

我们用 fruit.txt 和 company.txt 两个文件来向你演示 awk 同时处理多个文件的时候有什么效果

$ awk '{print FILENAME "\t" $0}' fruit.txt company.txt

fruit.txt       peach    100   Mar  1997   China

fruit.txt       Lemon    150   Jan  1986   America

fruit.txt       Pear     240   Mar  1990   Janpan

fruit.txt       avocado  120   Feb  2008   china

company.txt     yahoo   100 4500

company.txt     google  150 7500

company.txt     apple   180 8000

company.txt     twitter 120 5000

当你使用 awk 同时处理多个文件的时候,它会将多个文件合并处理,变量 FILENAME 就表示当前文本行所在的文件名称。

看到这里是不是感觉 awk 命令的使用方法真的是简单到爆炸,现在不要太高兴,请举起你的双手跟我一起摇摆。。。哦,不对!请拿起你的双手在电脑上试一试上面这些例子。 你会知道我没有骗你,因为讲了这么多,傻子都会了。。。—_—


BEGIN 关键字的使用

在脚本代码段前面使用 BEGIN 关键字时,它会在开始读取一个文件之前,运行一次 BEGIN 关键字后面的脚本代码段, BEGIN 后面的脚本代码段只会执行一次,执行完之后 awk 程序就会退出

$ awk 'BEGIN {print "Start read file"}' /etc/passwd

Start read file

awk 脚本中可以用多个花括号来执行多个脚本代码,就像下面这样

$ awk 'BEGIN {print "Start read file"} {print $0}' /etc/passwd

Start read file

root:x:0:0:root:/root:/bin/bash

bin:x:1:1:bin:/bin:/sbin/nologin

daemon:x:2:2:daemon:/sbin:/sbin/nologin

adm:x:3:4:adm:/var/adm:/sbin/nologin

lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin

sync:x:5:0:sync:/sbin:/bin/sync

shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown

halt:x:7:0:halt:/sbin:/sbin/halt

mail:x:8:12:mail:/var/spool/mail:/sbin/nologin

operator:x:11:0:operator:/root:/sbin/nologin

games:x:12:100:games:/usr/games:/sbin/nologin

ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin

nobody:x:99:99:Nobody:/:/sbin/nologin

END 关键字使用方法

awk 的 END 指令和 BEGIN 恰好相反,在 awk 读取并且处理完文件的所有内容行之后,才会执行 END 后面的脚本代码段

$ awk 'END {print "End file"}' /etc/passwd

End file

一定要多动手在电脑上敲一敲这些命令,对身体好。脑子是个好东西,要多用。。

$ awk 'BEGIN {print "Start read file"} {print $0} END {print "End file"}' /etc/passwd

Start read file

root:x:0:0:root:/root:/bin/bash

bin:x:1:1:bin:/bin:/sbin/nologin

daemon:x:2:2:daemon:/sbin:/sbin/nologin

adm:x:3:4:adm:/var/adm:/sbin/nologin

lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin

sync:x:5:0:sync:/sbin:/bin/sync

shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown

halt:x:7:0:halt:/sbin:/sbin/halt

mail:x:8:12:mail:/var/spool/mail:/sbin/nologin

operator:x:11:0:operator:/root:/sbin/nologin

games:x:12:100:games:/usr/games:/sbin/nologin

ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin

nobody:x:99:99:Nobody:/:/sbin/nologin

End file

在 awk 中使用变量

可以在 awk 脚本中声明和使用变量

$ awk '{msg="hello world"; print msg}' /etc/passwd

hello world

hello world

hello world

hello world

hello world

awk 声明的变量
可以在任何多个花括号脚本中使用

$ awk 'BEGIN {msg="hello world"} {print msg}' /etc/passwd

hello world

hello world

hello world

hello world

hello world

在 awk 中使用数学运算

在 awk 中,像其他编程语言一样,它也支持一些基本的数学运算操作

$ awk '{a = 12; b = 24; print a + b}' company.txt
36
36
36
36

上面这段脚本表示,先声明两个变量 a = 12 和 b = 24,然后用 print 打印出 a 加上 b 的结果。

看到上面的输出结果,你很可能又是一脸的懵逼,为什么会重复输出 4 次同样的计算结果。所以说小时不学好,长大做IT。 知识这东西真到了要用的时候,能亮瞎别人的双眼,好了,不废话。请记住 awk 是针对文件的每一行来执行一次单引号 里面的脚本代码,每读取到一行就会执行一次,文件里面有多少行就会执行多少次,但 BEGIN 和 END 关键字后面的 脚本代码除外,如果被处理的文件中什么都没有,那 awk 就一次都不会执行。。。

awk 还支持其他的数学运算符

+ 加法运算符

减法运算符
* 乘法运算符

/ 除法运算符

% 取余运算符

在 awk 中使用条件判断

比如有一个文件 company.txt 内容如下

yahoo   100 4500

google  150 7500

apple   180 8000

twitter 120 5000

我们要判断文件的第 3 列数据,也就是平均工资小于 5500 的公司,然后将其打印输出

$ awk '$3 < 5500 {print $0}' company.txt

yahoo   100 4500

twitter 120 5000

上面的命令结果就是平均工资小于 5500 的公司名单, $3 < 5500 表示当第 3 列字段的内容小于 5500 的时候才会执行后面的 {print $0} 代码块

$ awk '$1 == "yahoo" {print $0}' company.txt

yahoo   100 4500

awk 还有一些其他的条件操作符如下

< 小于

<= 小于或等于

== 等于

!= 不等于

大于

= 大于或等于

~ 匹配正则表达式

!~ 不匹配正则表达式

使用 if 指令判断来实现上面同样的效果

$ awk '{if ($3 < 5500) print $0}' company.txt

yahoo   100 4500

twitter 120 5000

上面表示如果第 3 列字段小于 5500 的时候就会执行后面的 print $0,很像 C 语言和 PHP 的语法对不对。 想到这里有一句话不知当讲不当讲,那就是 PHP 是世界上最好的语言。。。 我可能喝多了, 但是突然想起来我好像从来不喝酒。。。—_—

在 awk 中使用正则表达式

在 awk 中支持正则表达式的使用,如果你还对正则表达式不是很了解,请先停下来,上 google 去搜一下。

比如现在我们有这么一个文件 poetry.txt 里面都是我写的诗,不要问我为什么那么的有才华。内容如下:

This above all: to thine self be true

There is nothing either good or bad, but thinking makes it so

There’s a special providence in the fall of a sparrow

No matter how dark long, may eventually in the day arrival

使用正则表达式匹配字符串 “There” ,将包含这个字符串的行打印并输出

$ awk '/There/{print $0}' poetry.txt

There is nothing either good or bad, but thinking makes it so

There’s a special providence in the fall of a sparrow

使用正则表达式配一个包含字母 t 和字母 e ,并且 t 和 e 中间只能有任意单个字符的行

$ awk '/t.e/{print $0}' poetry.txt

There is nothing either good or bad, but thinking makes it so

There’s a special providence in the fall of a sparrow

No matter how dark long, may eventually in the day arrival

如果只想匹配单纯的字符串 “t.e”, 那正则表达式就是这样的 /t\.e/ ,用反斜杠来转义 . 符号 因为 . 在正则表达式里面表示任意单个字符。

使用正则表达式来匹配所有以 “The” 字符串开头的行

$ awk '/^The/{print $0}' poetry.txt

There is nothing either good or bad, but thinking makes it so

There’s a special providence in the fall of a sparrow

在正则表达式中 ^ 表示以某某字符或者字符串开头。

使用正则表达式来匹配所有以 “true” 字符串结尾的行

$ awk '/true$/{print $0}' poetry.txt

This above all: to thine self be true

在正则表达式中 $ 表示以某某字符或者字符串结尾。

又一个正则表达式例子如下

$ awk '/m[a]t/{print $0}' poetry.txt

No matter how dark long, may eventually in the day arrival

上面这个正则表达式 /m[a]t/ 表示匹配包含字符 m ,然后接着后面还要包含中间方括号中表示的单个字符 a ,最后还要包含字符 t 的行,输出结果中只有单词 “matter” 符合这个正则表达式的匹配。因为正则表达式 [a] 方括号中表示匹配里面的任意单个字符。

继续上面的一个新例子如下

$ awk '/^Th[ie]/{print $0}' poetry.txt

This above all: to thine self be true

There is nothing either good or bad, but thinking makes it so

There’s a special providence in the fall of a sparrow

这个例子中的正则表达式 /^Th[ie]/表示匹配以字符串 “Thi” 或者 “The” 开头的行,正则表达式方括号中表示匹配其中的任意单个字符。

再继续上面的新的用法

$ awk '/s[a-z]/{print $0}' poetry.txt

This above all: to thine self be true

There is nothing either good or bad, but thinking makes it so

There’s a special providence in the fall of a sparrow

正则表达式 /s[a-z]/ 表示匹配包含字符 s 然后后面跟着任意 a 到 z 之间的单个字符的字符串,比如 “se”, “so”, “sp” 等等。

正则表达式 [] 方括号中还有一些其他用法比如下面这些

[a-zA-Z]  表示匹配小写的 a 到 z 之间的单个字符,或者大写的 A 到 Z 之间的单个字符

[^a-z]    符号 `^` 在方括号里面表示取反,也就是非的意思,表示匹配任何非 a 到 z 之间的单个字符

正则表达式中的星号 * 和加号 + 的使用方法

$ awk '/go*d/{print $0}' poetry.txt

There is nothing either good or bad, but thinking makes it so

上面这个表示匹配包含字符串 “god”,并且中间的字母 “o” 可以出现 0 次或者多次,比如单词 “good” 就符合这个要求。 正则表达式中的 + 和星号原理差不多,只是加号表示任意 1 个或者 1 个以上,也就是必须至少要出现一次。

正则表达式问号 ? 的使用方法

$ awk '/ba?d/{print $0}' poetry.txt

There is nothing either good or bad, but thinking makes it so

正则表达式中的问号 ? 表示它前面的字符只能出现 0 次 或者 1 次,也就是可以不出现,也可以出现,但如果有出现也只能出现 1 次。

正则表达式中的 {} 花括号用法

$ awk '/go{2}d/{print $0}' poetry.txt

There is nothing either good or bad, but thinking makes it so

花括号 {} 表示规定它前面的字符必须出现的次数,像上面这个 /go{2}d/ 就表示只匹配字符串 “good”,也就是中间的字母 “o” 必须要出现 2 次。

正则表达式中的花括号还有一些其他的用法如下

/go{2,3}d/    表示字母 "o" 只能可以出现 2 次或者 3 次

/go{2,10}d/   表示字母 "o" 只能可以出现 2次,3次,4次,5次,6次 ... 一直到 10 次

/go{2,}d/     表示字母 "o" 必须至少出现 2 次或着 2 次以上

正则表达式中的圆括号的用法

$ awk '/th(in){1}king/{print $0}' poetry.txt

There is nothing either good or bad, but thinking makes it so

正则表达式中的圆括号表示将多个字符当成一个完整的对象来看待。比如 /th(in){1}king/ 就表示其中字符串 “in” 必须出现 1 次。而如果不加圆括号就变成了 /thin{1}king/ 这个就表示其中字符 “n” 必须出现 1 次。

看到这里,如果你对 poetry.txt 件中写的诗比较熟悉,你就会发现。。。我去!这诗根本就不是我写的。所以论多读书是多么的重要。我有幸借用莎士比亚的诗来向你讲解如何在 awk 中使用正则表达式。现在该想想晚上吃什么,晚上去吃火锅。。。—_—

使用 awk 的一些总结

因为 awk 算起来也是一种编程语言,它的功能远远不止我们上面讲的这些,awk 还有一些其他比较复杂的功能。但一般我们不建议将 awk 用的太过于复杂。通常面对一些比较复杂的场景我们还是要使用其他的一些工具,比如 shell 脚本,Lua 等等…… 查看全部
                                          详解 awk 工具的使用方法

详解 awk 工具的使用方法2017-05-22 程序员的那些事
来源:jarly
https://my.oschina.net/jarly/blog/898144
如有好文章投稿,请点击 → 这里了解详情

【伯乐在线转注】:awk 是一个强大的文本分析工具。它不仅是 Linux 中,也是任何环境中现有的功能最强大的数据处理引擎之一。相对于 grep 的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大。


当你第一次拿起双手在电脑上使用 awk 命令处理一个或者多个文件的时候,它会依次读取文件的每一行内容, 然后对其进行处理,awk 命令默认从 stdio 标准输入获取文件内容, awk 使用一对单引号来表示 一些可执行的脚本代码,在可执行脚本代码里面,使用一对花括号来表示一段可执行代码块,可以同时存在多个代码块。 awk 的每个花括号内同时又可以有多个指令,每一个指令用分号分隔,awk 其实就是一个脚本编程语言。说了这么多,你肯定还是一脸的懵逼。你猜对了,上面这些都是废话。先别急,客官请往下看……




awk 命令的基本格式

awk [options] 'program' file

options 这个表示一些可选的参数选项,反正就是你爱用不用,不用可以拉到。。。 program 这个表示 awk 的可执行脚本代码,这个是必须要有的。 file 这个表示 awk 需要处理的文件,注意是纯文本文件,不是你的 mp3,也不是 mp4 啥的。。

先来一个 awk 的使用例子热热身

$ awk '{print $0}' /etc/passwd

awk 命令的可执行脚本代码使用单引号括起来,紧接着里面是一对花括号,记住是 “花括号” 不是 “花姑娘”,然后花括号里面就是一些可执行的脚本代码段,当 awk 每读取一行之后,它会依次执行双引号里面的每个脚本代码段,在上面这个例子中, $0 表示当前行。当你执行了上面的命令之后,它会依次将 /etc/passwd 文件的每一行内容打印输出,你一定在想:这有个毛用,用 cat 命令也能搞定。没错!上面这个命令没个毛用,请往下看。

awk 自定义分隔符

awk 默认的分割符为空格和制表符,我们可以使用 -F 参数来指定分隔符

$ awk -F ':' '{print $1}' /etc/passwd

root

bin

daemon

adm

lp

sync

shutdown

halt

mail

operator

games

ftp

nobody

上面的命令将 /etc/passwd 文件中的每一行用冒号 : 分割成多个字段,然后用 print 将第 1 列字段的内容打印输出

如何在 awk 中同时指定多个分隔符

比如现在有这样一个文件 some.log 文件内容如下

Grape(100g)1980

raisins(500g)1990

plum(240g)1997

apricot(180g)2005

nectarine(200g)2008

现在我们想将上面的 some.log 文件中按照 “水果名称(重量)年份” 来进行分割

$ awk -F '[()]' '{print $1, $2, $3}' some.log

Grape 100g 1980

raisins 500g 1990

plum 240g 1997

apricot 180g 2005

nectarine 200g 2008

在 -F 参数中使用一对方括号来指定多个分隔符,awk 处理 some.log 文件时就会使用 “(” 和 “)” 来对文件的每一行进行分割。

awk 内置变量的使用

$0 这个表示文本处理时的当前行

$1 表示文本行被分隔后的第 1 个字段列

$2 表示文本行被分割后的第 2 个字段列

$3 表示文本行被分割后的第 3 个字段列

$n 表示文本行被分割后的第 n 个字段列

NR 表示文件中的行号,表示当前是第几行

NF 表示文件中的当前行列的个数,类似于 mysql 数据表里面每一条记录有多少个字段

FS 表示 awk 的输入分隔符,默认分隔符为空格和制表符,你可以对其进行自定义设置

OFS 表示 awk 的输出分隔符,默认为空格,你也可以对其进行自定义设置

FILENAME 表示当前文件的文件名称,如果同时处理多个文件,它也表示当前文件名称

比如我们有这么一个文本文件 fruit.txt 内容如下,我将用它来向你演示如何使用 awk 命令工具,顺便活跃一下此时尴尬的气氛。。

peach    100   Mar  1997   China

Lemon    150   Jan  1986   America

Pear     240   Mar  1990   Janpan

avocado  120   Feb  2008   china

我们来瞧一瞧下面这些简单到爆炸的例子,这个表示打印输出文件的每一整行的内容

$ awk '{print $0}' fruit.txt

peach    100   Mar  1997   China

Lemon    150   Jan  1986   America

Pear     240   Mar  1990   Janpan

avocado  120   Feb  2008   china

下面这个表示打印输出文件的每一行的第 1 列内容

$ awk '{print $1}' fruit.txt

peach

Lemon

Pear

avocado

下面面这个表示打印输出文件的每一行的第 1 列、第 2 列和第 3 列内容

$ awk '{print $1, $2, $3}' fruit.txt

peach 100 Mar

Lemon 150 Jan

Pear 240 Mar

avocado 120 Feb

其中加入的逗号表示插入输出分隔符,也就是默认的空格

文件的每一行的每一列的内容除了可以用 print 命令打印输出以外,还可以对其进行赋值

$ awk '{$2 = "***"; print $0}' fruit.txt

peach *** Mar 1997 China

Lemon *** Jan 1986 America

Pear *** Mar 1990 Janpan

avocado *** Feb 2008 china

上面的例子就是表示通过对 $2 变量进行重新赋值,来隐藏每一行的第 2 列内容,并且用星号 * 来代替其输出

在参数列表中加入一些字符串或者转义字符之类的东东

$ awk '{print $1 "\t" $2 "\t" $3}' fruit.txt

peach   100     Mar

Lemon   150     Jan

Pear    240     Mar

avocado 120     Feb

像上面这样,你可以在 print的参数列表中加入一些字符串或者转义字符之类的东东,让输出的内容格式更漂亮,但一定要记住要使用双引号。

awk 内置 NR 变量表示每一行的行号

$ awk '{print NR "\t" $0}' fruit.txt

1   peach    100   Mar  1997   China

2   Lemon    150   Jan  1986   America

3   Pear     240   Mar  1990   Janpan

4   avocado  120   Feb  2008   china

awk 内置 NF 变量表示每一行的列数

$ awk '{print NF "\t" $0}' fruit.txt

5   peach    100   Mar  1997   China

5   Lemon    150   Jan  1986   America

5   Pear     240   Mar  1990   Janpan

5   avocado  120   Feb  2008   china

awk 中 $NF 变量的使用

$ awk '{print $NF}' fruit.txt

China

America

Janpan

china

上面这个 $NF 就表示每一行的最后一列,因为 NF 表示一行的总列数,在这个文件里表示有 5 列,然后在其前面加上 $ 符号,就变成了 $5 ,表示第 5 列

$ awk '{print $(NF - 1)}' fruit.txt

1997

1986

1990

2008

上面 $(NF-1) 表示倒数第 2 列, $(NF-2) 表示倒数第 3 列,依次类推。

yahoo   100 4500

google  150 7500

apple   180 8000

twitter 120 5000

我们用 fruit.txt 和 company.txt 两个文件来向你演示 awk 同时处理多个文件的时候有什么效果

$ awk '{print FILENAME "\t" $0}' fruit.txt company.txt

fruit.txt       peach    100   Mar  1997   China

fruit.txt       Lemon    150   Jan  1986   America

fruit.txt       Pear     240   Mar  1990   Janpan

fruit.txt       avocado  120   Feb  2008   china

company.txt     yahoo   100 4500

company.txt     google  150 7500

company.txt     apple   180 8000

company.txt     twitter 120 5000

当你使用 awk 同时处理多个文件的时候,它会将多个文件合并处理,变量 FILENAME 就表示当前文本行所在的文件名称。

看到这里是不是感觉 awk 命令的使用方法真的是简单到爆炸,现在不要太高兴,请举起你的双手跟我一起摇摆。。。哦,不对!请拿起你的双手在电脑上试一试上面这些例子。 你会知道我没有骗你,因为讲了这么多,傻子都会了。。。—_—


BEGIN 关键字的使用

在脚本代码段前面使用 BEGIN 关键字时,它会在开始读取一个文件之前,运行一次 BEGIN 关键字后面的脚本代码段, BEGIN 后面的脚本代码段只会执行一次,执行完之后 awk 程序就会退出

$ awk 'BEGIN {print "Start read file"}' /etc/passwd

Start read file

awk 脚本中可以用多个花括号来执行多个脚本代码,就像下面这样

$ awk 'BEGIN {print "Start read file"} {print $0}' /etc/passwd

Start read file

root:x:0:0:root:/root:/bin/bash

bin:x:1:1:bin:/bin:/sbin/nologin

daemon:x:2:2:daemon:/sbin:/sbin/nologin

adm:x:3:4:adm:/var/adm:/sbin/nologin

lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin

sync:x:5:0:sync:/sbin:/bin/sync

shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown

halt:x:7:0:halt:/sbin:/sbin/halt

mail:x:8:12:mail:/var/spool/mail:/sbin/nologin

operator:x:11:0:operator:/root:/sbin/nologin

games:x:12:100:games:/usr/games:/sbin/nologin

ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin

nobody:x:99:99:Nobody:/:/sbin/nologin

END 关键字使用方法

awk 的 END 指令和 BEGIN 恰好相反,在 awk 读取并且处理完文件的所有内容行之后,才会执行 END 后面的脚本代码段

$ awk 'END {print "End file"}' /etc/passwd

End file

一定要多动手在电脑上敲一敲这些命令,对身体好。脑子是个好东西,要多用。。

$ awk 'BEGIN {print "Start read file"} {print $0} END {print "End file"}' /etc/passwd

Start read file

root:x:0:0:root:/root:/bin/bash

bin:x:1:1:bin:/bin:/sbin/nologin

daemon:x:2:2:daemon:/sbin:/sbin/nologin

adm:x:3:4:adm:/var/adm:/sbin/nologin

lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin

sync:x:5:0:sync:/sbin:/bin/sync

shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown

halt:x:7:0:halt:/sbin:/sbin/halt

mail:x:8:12:mail:/var/spool/mail:/sbin/nologin

operator:x:11:0:operator:/root:/sbin/nologin

games:x:12:100:games:/usr/games:/sbin/nologin

ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin

nobody:x:99:99:Nobody:/:/sbin/nologin

End file

在 awk 中使用变量

可以在 awk 脚本中声明和使用变量

$ awk '{msg="hello world"; print msg}' /etc/passwd

hello world

hello world

hello world

hello world

hello world

awk 声明的变量
可以在任何多个花括号脚本中使用

$ awk 'BEGIN {msg="hello world"} {print msg}' /etc/passwd

hello world

hello world

hello world

hello world

hello world

在 awk 中使用数学运算

在 awk 中,像其他编程语言一样,它也支持一些基本的数学运算操作

$ awk '{a = 12; b = 24; print a + b}' company.txt
36
36
36
36

上面这段脚本表示,先声明两个变量 a = 12 和 b = 24,然后用 print 打印出 a 加上 b 的结果。

看到上面的输出结果,你很可能又是一脸的懵逼,为什么会重复输出 4 次同样的计算结果。所以说小时不学好,长大做IT。 知识这东西真到了要用的时候,能亮瞎别人的双眼,好了,不废话。请记住 awk 是针对文件的每一行来执行一次单引号 里面的脚本代码,每读取到一行就会执行一次,文件里面有多少行就会执行多少次,但 BEGIN 和 END 关键字后面的 脚本代码除外,如果被处理的文件中什么都没有,那 awk 就一次都不会执行。。。

awk 还支持其他的数学运算符

+ 加法运算符

  • 减法运算符

* 乘法运算符

/ 除法运算符

% 取余运算符

在 awk 中使用条件判断

比如有一个文件 company.txt 内容如下

yahoo   100 4500

google  150 7500

apple   180 8000

twitter 120 5000

我们要判断文件的第 3 列数据,也就是平均工资小于 5500 的公司,然后将其打印输出

$ awk '$3 < 5500 {print $0}' company.txt

yahoo   100 4500

twitter 120 5000

上面的命令结果就是平均工资小于 5500 的公司名单, $3 < 5500 表示当第 3 列字段的内容小于 5500 的时候才会执行后面的 {print $0} 代码块

$ awk '$1 == "yahoo" {print $0}' company.txt

yahoo   100 4500

awk 还有一些其他的条件操作符如下

< 小于

<= 小于或等于

== 等于

!= 不等于

大于



= 大于或等于



~ 匹配正则表达式

!~ 不匹配正则表达式

使用 if 指令判断来实现上面同样的效果

$ awk '{if ($3 < 5500) print $0}' company.txt

yahoo   100 4500

twitter 120 5000

上面表示如果第 3 列字段小于 5500 的时候就会执行后面的 print $0,很像 C 语言和 PHP 的语法对不对。 想到这里有一句话不知当讲不当讲,那就是 PHP 是世界上最好的语言。。。 我可能喝多了, 但是突然想起来我好像从来不喝酒。。。—_—

在 awk 中使用正则表达式

在 awk 中支持正则表达式的使用,如果你还对正则表达式不是很了解,请先停下来,上 google 去搜一下。

比如现在我们有这么一个文件 poetry.txt 里面都是我写的诗,不要问我为什么那么的有才华。内容如下:

This above all: to thine self be true

There is nothing either good or bad, but thinking makes it so

There’s a special providence in the fall of a sparrow

No matter how dark long, may eventually in the day arrival

使用正则表达式匹配字符串 “There” ,将包含这个字符串的行打印并输出

$ awk '/There/{print $0}' poetry.txt

There is nothing either good or bad, but thinking makes it so

There’s a special providence in the fall of a sparrow

使用正则表达式配一个包含字母 t 和字母 e ,并且 t 和 e 中间只能有任意单个字符的行

$ awk '/t.e/{print $0}' poetry.txt

There is nothing either good or bad, but thinking makes it so

There’s a special providence in the fall of a sparrow

No matter how dark long, may eventually in the day arrival

如果只想匹配单纯的字符串 “t.e”, 那正则表达式就是这样的 /t\.e/ ,用反斜杠来转义 . 符号 因为 . 在正则表达式里面表示任意单个字符。

使用正则表达式来匹配所有以 “The” 字符串开头的行

$ awk '/^The/{print $0}' poetry.txt

There is nothing either good or bad, but thinking makes it so

There’s a special providence in the fall of a sparrow

在正则表达式中 ^ 表示以某某字符或者字符串开头。

使用正则表达式来匹配所有以 “true” 字符串结尾的行

$ awk '/true$/{print $0}' poetry.txt

This above all: to thine self be true

在正则表达式中 $ 表示以某某字符或者字符串结尾。

又一个正则表达式例子如下

$ awk '/m[a]t/{print $0}' poetry.txt

No matter how dark long, may eventually in the day arrival

上面这个正则表达式 /m[a]t/ 表示匹配包含字符 m ,然后接着后面还要包含中间方括号中表示的单个字符 a ,最后还要包含字符 t 的行,输出结果中只有单词 “matter” 符合这个正则表达式的匹配。因为正则表达式 [a] 方括号中表示匹配里面的任意单个字符。

继续上面的一个新例子如下

$ awk '/^Th[ie]/{print $0}' poetry.txt

This above all: to thine self be true

There is nothing either good or bad, but thinking makes it so

There’s a special providence in the fall of a sparrow

这个例子中的正则表达式 /^Th[ie]/表示匹配以字符串 “Thi” 或者 “The” 开头的行,正则表达式方括号中表示匹配其中的任意单个字符。

再继续上面的新的用法

$ awk '/s[a-z]/{print $0}' poetry.txt

This above all: to thine self be true

There is nothing either good or bad, but thinking makes it so

There’s a special providence in the fall of a sparrow

正则表达式 /s[a-z]/ 表示匹配包含字符 s 然后后面跟着任意 a 到 z 之间的单个字符的字符串,比如 “se”, “so”, “sp” 等等。

正则表达式 [] 方括号中还有一些其他用法比如下面这些

[a-zA-Z]  表示匹配小写的 a 到 z 之间的单个字符,或者大写的 A 到 Z 之间的单个字符

[^a-z]    符号 `^` 在方括号里面表示取反,也就是非的意思,表示匹配任何非 a 到 z 之间的单个字符

正则表达式中的星号 * 和加号 + 的使用方法

$ awk '/go*d/{print $0}' poetry.txt

There is nothing either good or bad, but thinking makes it so

上面这个表示匹配包含字符串 “god”,并且中间的字母 “o” 可以出现 0 次或者多次,比如单词 “good” 就符合这个要求。 正则表达式中的 + 和星号原理差不多,只是加号表示任意 1 个或者 1 个以上,也就是必须至少要出现一次。

正则表达式问号 ? 的使用方法

$ awk '/ba?d/{print $0}' poetry.txt

There is nothing either good or bad, but thinking makes it so

正则表达式中的问号 ? 表示它前面的字符只能出现 0 次 或者 1 次,也就是可以不出现,也可以出现,但如果有出现也只能出现 1 次。

正则表达式中的 {} 花括号用法

$ awk '/go{2}d/{print $0}' poetry.txt

There is nothing either good or bad, but thinking makes it so

花括号 {} 表示规定它前面的字符必须出现的次数,像上面这个 /go{2}d/ 就表示只匹配字符串 “good”,也就是中间的字母 “o” 必须要出现 2 次。

正则表达式中的花括号还有一些其他的用法如下

/go{2,3}d/    表示字母 "o" 只能可以出现 2 次或者 3 次

/go{2,10}d/   表示字母 "o" 只能可以出现 2次,3次,4次,5次,6次 ... 一直到 10 次

/go{2,}d/     表示字母 "o" 必须至少出现 2 次或着 2 次以上

正则表达式中的圆括号的用法

$ awk '/th(in){1}king/{print $0}' poetry.txt

There is nothing either good or bad, but thinking makes it so

正则表达式中的圆括号表示将多个字符当成一个完整的对象来看待。比如 /th(in){1}king/ 就表示其中字符串 “in” 必须出现 1 次。而如果不加圆括号就变成了 /thin{1}king/ 这个就表示其中字符 “n” 必须出现 1 次。

看到这里,如果你对 poetry.txt 件中写的诗比较熟悉,你就会发现。。。我去!这诗根本就不是我写的。所以论多读书是多么的重要。我有幸借用莎士比亚的诗来向你讲解如何在 awk 中使用正则表达式。现在该想想晚上吃什么,晚上去吃火锅。。。—_—

使用 awk 的一些总结

因为 awk 算起来也是一种编程语言,它的功能远远不止我们上面讲的这些,awk 还有一些其他比较复杂的功能。但一般我们不建议将 awk 用的太过于复杂。通常面对一些比较复杂的场景我们还是要使用其他的一些工具,比如 shell 脚本,Lua 等等……

Bash快捷键-光标移到行首、行尾等

Mosuan 发表了文章 • 3 个评论 • 882 次浏览 • 2017-01-11 11:03 • 来自相关话题

转自@http://blog.csdn.net/force_eagle/article/details/7999153
 
ctrl键组合
ctrl+a:光标移到行首。
ctrl+b:光标左移一个字母
ctrl+c:杀死当前进程。
ctrl+d:退出当前 Shell。
ctrl+e:光标移到行尾。
ctrl+h:删除光标前一个字符,同 backspace 键相同。
ctrl+k:清除光标后至行尾的内容。
ctrl+l:清屏,相当于clear。
ctrl+r:搜索之前打过的命令。会有一个提示,根据你输入的关键字进行搜索bash的history
ctrl+u: 清除光标前至行首间的所有内容。
ctrl+w: 移除光标前的一个单词
ctrl+t: 交换光标位置前的两个字符
ctrl+y: 粘贴或者恢复上次的删除
ctrl+d: 删除光标所在字母;注意和backspace以及ctrl+h的区别,这2个是删除光标前的字符
ctrl+f: 光标右移
ctrl+z : 把当前进程转到后台运行,使用’ fg ‘命令恢复。比如top -d1 然后ctrl+z ,到后台,然后fg,重新恢复
esc组合
esc+d: 删除光标后的一个词
esc+f: 往右跳一个词
esc+b: 往左跳一个词
esc+t: 交换光标位置前的两个单词。 查看全部
转自@http://blog.csdn.net/force_eagle/article/details/7999153
 
ctrl键组合
ctrl+a:光标移到行首。
ctrl+b:光标左移一个字母
ctrl+c:杀死当前进程。
ctrl+d:退出当前 Shell。
ctrl+e:光标移到行尾。
ctrl+h:删除光标前一个字符,同 backspace 键相同。
ctrl+k:清除光标后至行尾的内容。
ctrl+l:清屏,相当于clear。
ctrl+r:搜索之前打过的命令。会有一个提示,根据你输入的关键字进行搜索bash的history
ctrl+u: 清除光标前至行首间的所有内容。
ctrl+w: 移除光标前的一个单词
ctrl+t: 交换光标位置前的两个字符
ctrl+y: 粘贴或者恢复上次的删除
ctrl+d: 删除光标所在字母;注意和backspace以及ctrl+h的区别,这2个是删除光标前的字符
ctrl+f: 光标右移
ctrl+z : 把当前进程转到后台运行,使用’ fg ‘命令恢复。比如top -d1 然后ctrl+z ,到后台,然后fg,重新恢复
esc组合
esc+d: 删除光标后的一个词
esc+f: 往右跳一个词
esc+b: 往左跳一个词
esc+t: 交换光标位置前的两个单词。

分享一个随机生成固定时间段固定格式的EXCEL公式

TaeJa 发表了文章 • 3 个评论 • 505 次浏览 • 2016-09-14 16:20 • 来自相关话题

如图





 
利用EXCEL随机生成2016-09-12到2016-09-20的每天9:00-23:59:59且格式为 YYYYMMDDHHMMSS的时间字符串
公式如下:
=TEXT(RAND()+"2016-09-20","yyyymmdd")&TEXT(RAND()+"9:0","hhmmss")
 





如图往一下一拉你想要的时间串就出来啦 这个东西大家以后工作中一定会超级有用的 收藏在这以后就不用每次都去百度啦  当然大牛可以完全无视~这东西可以自己写个脚本生成嘛 但是为了提高工作效率 还是建议大家用EXCEL最简便啦~
 
另外 在这里跟大家提一下 Xshell这个东西是很强大的 可以代替SCP跟linux进行二进制传输的,Xshell这个东西是很强大的 可以代替SCP跟linux进行二进制传输的,Xshell这个东西是很强大的 可以代替SCP跟linux进行二进制传输的,重要的事情讲三遍,你想传东西到linux里时试试直接把文件拖进Xshell框里,是不是非常方便呢 超级提高工作效率的!!! 再也不用每次都要打开SCP才能传东西了!!
 
 
  查看全部
如图

1.png

 
利用EXCEL随机生成2016-09-12到2016-09-20的每天9:00-23:59:59且格式为 YYYYMMDDHHMMSS的时间字符串
公式如下:
=TEXT(RAND()+"2016-09-20","yyyymmdd")&TEXT(RAND()+"9:0","hhmmss")
 

2.png

如图往一下一拉你想要的时间串就出来啦 这个东西大家以后工作中一定会超级有用的 收藏在这以后就不用每次都去百度啦  当然大牛可以完全无视~这东西可以自己写个脚本生成嘛 但是为了提高工作效率 还是建议大家用EXCEL最简便啦~
 
另外 在这里跟大家提一下 Xshell这个东西是很强大的 可以代替SCP跟linux进行二进制传输的,Xshell这个东西是很强大的 可以代替SCP跟linux进行二进制传输的,Xshell这个东西是很强大的 可以代替SCP跟linux进行二进制传输的,重要的事情讲三遍,你想传东西到linux里时试试直接把文件拖进Xshell框里,是不是非常方便呢 超级提高工作效率的!!! 再也不用每次都要打开SCP才能传东西了!!
 
 
 

shell里写循环时 Bad for loop variable解决办法

TaeJa 发表了文章 • 1 个评论 • 461 次浏览 • 2016-09-14 14:32 • 来自相关话题

很多时候在shell里写一个循环 从头到尾检查了N遍也查不出错 但一运行就是报错 如图





 
简单的小循环都报错





 
错误为Syntax error: Bad for loop variable


解决办法:sudo dpkg-reconfigure dash
在选择项中选No

从 ubuntu 6.10 开始,ubuntu 就将先前默认的bash shell 更换成了dash shell;其表现为 /bin/sh 链接倒了/bin/dash而不是传统的/bin/bash。

ubuntu edgy是第一个将dash作为默认shell来发行的版本,这似乎是受了debian的影响。wiki 里面有官方的解释,




,主要原因是dash更小,运行更快,还与POSIX兼容。

但 目前存在的问题是,由于shell的更换,致使很多脚本出错,毕竟现在的很多脚本不是100%POSIX兼容。

在wiki里面也说到,如 何将默认的shell改回bash,方法就是

在终端执行 sudo dpkg-reconfigure dash

然后选 择 no





 





 
改回bash成功
 
再次运行循环脚本就不会报错啦~~
 
  查看全部
很多时候在shell里写一个循环 从头到尾检查了N遍也查不出错 但一运行就是报错 如图

1.png

 
简单的小循环都报错

2.png

 
错误为Syntax error: Bad for loop variable


解决办法:sudo dpkg-reconfigure dash
在选择项中选No

从 ubuntu 6.10 开始,ubuntu 就将先前默认的bash shell 更换成了dash shell;其表现为 /bin/sh 链接倒了/bin/dash而不是传统的/bin/bash。

ubuntu edgy是第一个将dash作为默认shell来发行的版本,这似乎是受了debian的影响。wiki 里面有官方的解释,
5.png

,主要原因是dash更小,运行更快,还与POSIX兼容。

但 目前存在的问题是,由于shell的更换,致使很多脚本出错,毕竟现在的很多脚本不是100%POSIX兼容。

在wiki里面也说到,如 何将默认的shell改回bash,方法就是

在终端执行 sudo dpkg-reconfigure dash

然后选 择 no

3.png

 

4.png

 
改回bash成功
 
再次运行循环脚本就不会报错啦~~
 
 

那些年我们踩得那些shell坑(四)

ttgo2 发表了文章 • 3 个评论 • 387 次浏览 • 2016-09-07 17:44 • 来自相关话题

0x01 系统环境
 
操作系统:redhat linux 6
shell环境:bash shell
 
0x02 坑位说明
 
$? 是用来判定上次grep的匹配是否成功,1表示失败,0表示成功,相信大家都掌握了。。
 
0x03 运行结果
 
[root@localhost ~]# cat /etc/passwd | grep root
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
[root@localhost ~]# echo $?
0
[root@localhost ~]# cat /etc/passwd | grep root123
[root@localhost ~]# echo $?
1
[root@localhost ~]# 
 
0x04 问题出现
 
[root@localhost ~]# grep ????????
: ??????????
[root@localhost ~]# echo $?
2
 
 
什么情况下出现2个判断?明天公布答案。。。。
 
 
 
 
  查看全部
0x01 系统环境
 
操作系统:redhat linux 6
shell环境:bash shell
 
0x02 坑位说明
 
$? 是用来判定上次grep的匹配是否成功,1表示失败,0表示成功,相信大家都掌握了。。
 
0x03 运行结果
 
[root@localhost ~]# cat /etc/passwd | grep root
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
[root@localhost ~]# echo $?
0
[root@localhost ~]# cat /etc/passwd | grep root123
[root@localhost ~]# echo $?
1
[root@localhost ~]# 
 
0x04 问题出现
 
[root@localhost ~]# grep ????????
: ??????????
[root@localhost ~]# echo $?
2

 
 
什么情况下出现2个判断?明天公布答案。。。。
 
 
 
 
 

那些年我们踩得那些shell坑(三)

ttgo2 发表了文章 • 13 个评论 • 425 次浏览 • 2016-09-07 10:24 • 来自相关话题

0x01 测试环境
 
[]系统类型:redhat linux 6.0[/][]shell类型:bash shell[/]
 
0x02 坑位描述(cp复制命令卡壳了)
 
复制cp命令使用频率很多,,很多时候大家没有在这个地方栽过跟头,有一次被郁闷了,这次的文件名比较奇葩,文件名为“-reg.log”,把文件复制到/tmp 目录下,出现参数问题,,
 
0x03 代码如下
 
[root@localhost test]# touch -- -reg.log

[root@localhost test]# cp -reg.log /tmp/

cp:无效选项 -- e

请尝试执行"cp --help"来获取更多信息。

[root@localhost test]# 
 
0x04坑位分析
 
原因是文件前面有一个“-”,导致当成参数执行了。
 
0x05 三思一下
 
大家自己先自己想一下,,可以积极回复,, 查看全部
0x01 测试环境
 
    []系统类型:redhat linux 6.0[/][]shell类型:bash shell[/]

 
0x02 坑位描述(cp复制命令卡壳了)
 
复制cp命令使用频率很多,,很多时候大家没有在这个地方栽过跟头,有一次被郁闷了,这次的文件名比较奇葩,文件名为“-reg.log”,把文件复制到/tmp 目录下,出现参数问题,,
 
0x03 代码如下
 
[root@localhost test]# touch -- -reg.log

[root@localhost test]# cp -reg.log /tmp/

cp:无效选项 -- e

请尝试执行"cp --help"来获取更多信息。

[root@localhost test]# 
 
0x04坑位分析
 
原因是文件前面有一个“-”,导致当成参数执行了。
 
0x05 三思一下
 
大家自己先自己想一下,,可以积极回复,,

那些年我们踩得那些shell坑(二)

ttgo2 发表了文章 • 6 个评论 • 461 次浏览 • 2016-09-06 17:39 • 来自相关话题

0x01 测试环境
 
OS:red hat 6.8
shell: bash shell
 
0x02 字符串“迷踪拳”
 
比较字符串是否相等?具体情况代码,,(看不懂的小白自行脑补。。)
 
#!/bin/bash
str1="tom"
str2="cat"
if [ "$str1"=="$str2" ]; then
echo "string is same"
else
echo "string is no same"
fi
 
 
0x03 测试结果
 
结果是什么呢?大家思考一下在往下看结果。。。。





 
0x04 坑位置
 
问题发生那里?大家是否可以自己思考一下?,有明白的可以抢先回答,稍后给大家公布答案?
 
0x05 答案公布
 
if 判断字符串的时候,记得在“==”两边加上空格
 
#!/bin/bash
str1="tom"
str2="cat"
if [ "$str1" == "$str2" ]; then
echo "string is same"
else
echo "string is no same"
fi
  查看全部
0x01 测试环境
 
OS:red hat 6.8
shell: bash shell
 
0x02 字符串“迷踪拳”
 
比较字符串是否相等?具体情况代码,,(看不懂的小白自行脑补。。)
 
#!/bin/bash
str1="tom"
str2="cat"
if [ "$str1"=="$str2" ]; then
echo "string is same"
else
echo "string is no same"
fi
 
 
0x03 测试结果
 
结果是什么呢?大家思考一下在往下看结果。。。。

QQ截图20160906173432.png

 
0x04 坑位置
 
问题发生那里?大家是否可以自己思考一下?,有明白的可以抢先回答,稍后给大家公布答案?
 
0x05 答案公布
 
if 判断字符串的时候,记得在“==”两边加上空格
 
#!/bin/bash
str1="tom"
str2="cat"
if [ "$str1" == "$str2" ]; then
echo "string is same"
else
echo "string is no same"
fi

 

那些年我们踩得那些shell坑(一)

ttgo2 发表了文章 • 12 个评论 • 533 次浏览 • 2016-09-06 09:49 • 来自相关话题

0x1 环境介绍
 
  操作系统:red hat 6.8
 
  shell 类型:bash shell
 
0x2需求介绍
  
  循环输出目录下的".txt"文件(很简单吧。。。^^),那就边做边看吧。。。下面是目录下的文件
[root@localhost test]# ll

总用量 4

-rw-r--r--. 1 root root  0  8月 24 21:01 1- re.txt

-rw-r--r--. 1 root root  0  8月 24 21:01 2- re.txt

-rw-r--r--. 1 root root  0  8月 24 21:17 3.mp3

-rw-r--r--. 1 root root  0  8月 24 21:01 3- re.txt

-rw-r--r--. 1 root root  0  8月 24 21:17 4.mp3

-rwxr-xr-x. 1 root root 44  8月 24 21:09 for.sh

[root@localhost test]# 

0x3脚本开写, 如下;
 
#!/bin/bash
for i in `ls *.txt`;
do
echo $i
done

0x4运行结果,如下;
 
[root@localhost test]# ./for.sh 

1-

re.txt

2-

re.txt

3-

re.txt
 
这是什么鬼。。。跟自己想的完全不一样了
 
0x5坑位置
 
为什么会出现这样的问题呢? 因为for in 是根据空白符来分词的。。 是不是明白了?我们的文件名中间有空格,导致了这个问题
 
0x6 调整姿势
 
增加双引号,,改一下脚本,看看是否OK?
 
[root@localhost test]# cat for.sh 

#!/bin/bash

for i in "`ls *.txt`";

do

echo $i

done
 
测试结果

[root@localhost test]# ./for.sh 

1- re.txt 2- re.txt 3- re.txt    -----成了一个整体输出了,也不对
 
 
 
0x7 一起来
 
大家自己试试,,,稍后公布答案,,踊跃参加呀。。。。。
 
 0x8 答案揭晓 
 
#!/bin/bash
for i in *.txt;
do
echo $i
done
 
  查看全部
0x1 环境介绍
 
  操作系统:red hat 6.8
 
  shell 类型:bash shell
 
0x2需求介绍
  
  循环输出目录下的".txt"文件(很简单吧。。。^^),那就边做边看吧。。。下面是目录下的文件
[root@localhost test]# ll

总用量 4

-rw-r--r--. 1 root root  0  8月 24 21:01 1- re.txt

-rw-r--r--. 1 root root  0  8月 24 21:01 2- re.txt

-rw-r--r--. 1 root root  0  8月 24 21:17 3.mp3

-rw-r--r--. 1 root root  0  8月 24 21:01 3- re.txt

-rw-r--r--. 1 root root  0  8月 24 21:17 4.mp3

-rwxr-xr-x. 1 root root 44  8月 24 21:09 for.sh

[root@localhost test]# 

0x3脚本开写, 如下;
 
#!/bin/bash
for i in `ls *.txt`;
do
echo $i
done

0x4运行结果,如下;
 
[root@localhost test]# ./for.sh 

1-

re.txt

2-

re.txt

3-

re.txt

 
这是什么鬼。。。跟自己想的完全不一样了
 
0x5坑位置
 
为什么会出现这样的问题呢? 因为for in 是根据空白符来分词的。。 是不是明白了?我们的文件名中间有空格,导致了这个问题
 
0x6 调整姿势
 
增加双引号,,改一下脚本,看看是否OK?
 
[root@localhost test]# cat for.sh 

#!/bin/bash

for i in "`ls *.txt`";

do

echo $i

done
 
测试结果

[root@localhost test]# ./for.sh 

1- re.txt 2- re.txt 3- re.txt    -----成了一个整体输出了,也不对
 
 
 
0x7 一起来
 
大家自己试试,,,稍后公布答案,,踊跃参加呀。。。。。
 
 0x8 答案揭晓 
 

#!/bin/bash
for i in *.txt;
do
echo $i
done