Linux随笔6-软件安装以及sed和bash变量删除、替换

Linux随笔6-软件安装以及sed和bash变量删除、替换

关于Linux上的软件安装,主要途径有源码编译安装、二进制文件安装(比如RedHat以及其衍生版的二进制安装包.rpm以及Debian以及其衍生版的二进制安装包.deb)。而二进制安装包之间,往往会有依赖关系,为了解决各个二进制安装包之间的依赖关系,Debian发布了apt工具用于自动解决所安装的软件包的依赖关系;而RedHat后续也发布了与其发布版对应的yum工具来解决所安装软件包的依赖关系。这两个工具都需要依赖于后端的软件仓库,才能自动下载依赖的其他软件包。所以这里将会以yum工具的软件仓库配置进行介绍。随后会以编译安装http-2.4的实例过程说明如何通过源代码编译安装所需要的软件,以及安装之后的环境设置。

随后将会结合具体的示例介绍sed命令以及bash的变量内容替换、删除和截取。

1. 自建yum仓库

关于yum仓库仓库的配置,可以通常是通过安装系统的光盘镜像iso文件或者通过网络源进行配置,此处基于CentOS 7.6分别进行介绍。

1.1. 构建yum仓库的网络源

网络源采用fedora项目的EPEL(Extra Packages for Enterprise Linux)企业级Linux扩展软件源,从fedora项目网站下载对应版本的EPEL源的rpm包,https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm,具体如下:

[root@c7u6m1 opt]# wget https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
--2021-04-17 11:17:11--  https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
Resolving dl.fedoraproject.org (dl.fedoraproject.org)... 38.145.60.23, 38.145.60.24, 38.145.60.22
Connecting to dl.fedoraproject.org (dl.fedoraproject.org)|38.145.60.23|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 15448 (15K) [application/x-rpm]
Saving to: ‘epel-release-latest-7.noarch.rpm’

100%[=======================================================================================================>] 15,448      56.9KB/s   in 0.3s   

2021-04-17 11:17:18 (56.9 KB/s) - ‘epel-release-latest-7.noarch.rpm’ saved [15448/15448]

[root@c7u6m1 opt]# ls 
containerd  epel-release-latest-7.noarch.rpm  rh
[root@c7u6m1 opt]# rpm -ivh epel-release-latest-7.noarch.rpm 
Preparing...                          ################################# [100%]
     file /etc/yum.repos.d/epel-testing.repo from install of epel-release-7-13.noarch conflicts with file from package epel-release-7-11.noarch        file /etc/yum.repos.d/epel.repo from install of epel-release-7-13.noarch conflicts with file from package epel-release-7-11.noarch
     file /usr/lib/systemd/system-preset/90-epel.preset from install of epel-release-7-13.noarch conflicts with file from package epel-release-7-11.noarch
[root@c7u6m1 opt]# rpm -qa | egrep epel
epel-release-7-11.noarch
[root@c7u6m1 opt]# 
[root@c7u6m1 opt]# rpm -Uvh epel-release-latest-7.noarch.rpm
Preparing...                          ################################# [100%]
Updating / installing...   1:epel-release-7-13                ################################# [ 50%]
Cleaning up / removing...
2:epel-release-7-11                ################################# [100%]
[root@c7u6m1 opt]# 

由于此前安装过epel的rpm包,所以使用rpm -ivh安装的时候提示两个版本冲突。所以使用rpm -Uvh进行更新安装。安装完成之后,查看这个包中提供了哪些文件:

[root@c7u6m1 yum.repos.d]# rpm -ql epel-release 
/etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7
/etc/yum.repos.d/epel-testing.repo
/etc/yum.repos.d/epel.repo
/usr/lib/systemd/system-preset/90-epel.preset
/usr/share/doc/epel-release-7
/usr/share/doc/epel-release-7/GPL
[root@c7u6m1 yum.repos.d]#
[root@c7u6m1 yum.repos.d]# ls /etc/yum.repos.d/ | egrep epel
epel.repo
epel-testing.repo

至此,就安装完成了。

查看EPEL的镜像信息:

[root@c7u6m1 yum.repos.d]# yum repolist 
Loaded plugins: fastestmirror, langpacks
Repository epel is listed more than once in the configuration
Repository epel-debuginfo is listed more than once in the configuration
Repository epel-source is listed more than once in the configuration
Loading mirror speeds from cached hostfile
repo id                     repo name                      status
DVD-REPO                    CentOS 7.6 DVD Repository      4,021
base/7/x86_64               CentOS-7 - Base                10,072
docker-ce-stable/7/x86_64   Docker CE Stable - x86_64      112
epel/x86_64                 Extra Packages for Enterprise Linux 7 - x86_64    13,580
extras/7/x86_64             CentOS-7 - Extras              468
updates/7/x86_64            CentOS-7 - Updates             1,932
repolist: 30,185
[root@c7u6m1 yum.repos.d]# 

上述就构建好了网络源作为yum的软件包仓库。

1.2. 构建yum仓库的本地源

本地软件镜像源

  1. 向虚拟机中附加光盘镜像并挂载镜像

    向KVM虚拟机中附加ISO光盘镜像,具体命令如下所示:

    [root@localhost CentOS7.6]# virsh attach-disk c7u6m1 ${PWD}/CentOS-7-x86_64-DVD-1810.iso hda --type cdrom --mode readonly
    Disk attached successfully
    
    [root@localhost CentOS7.6]# virsh dumpxml c7u6m1 | egrep -C 3 CentOS
     </disk>
     <disk type='file' device='cdrom'>
       <driver name='qemu' type='raw'/>
       <source file='/data/iso/CentOS7.6/CentOS-7-x86_64-DVD-1810.iso' index='5'/>
       <backingStore/>
       <target dev='hda' bus='ide'/>
       <readonly/>
    [root@localhost CentOS7.6]# 
    

    查看附加好的光盘镜像:

    [root@c7u6m1 ~]# lsblk
    NAME         MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
    sr0           11:0    1  4.3G  0 rom  
    vda          252:0    0   40G  0 disk 
    ├─vda1       252:1    0  512M  0 part /boot
    ├─vda2       252:2    0    1G  0 part [SWAP]
    └─vda3       252:3    0 38.5G  0 part 
    └─vg0-root 253:0    0 38.5G  0 lvm  /
    [root@c7u6m1 ~]# ls -lh /dev/cdrom 
    lrwxrwxrwx 1 root root 3 Apr 17 09:56 /dev/cdrom -> sr0
    [root@c7u6m1 ~]# ls -lh /dev/sr0 
    brw-rw---- 1 root cdrom 11, 0 Apr 17 09:56 /dev/sr0
    [root@c7u6m1 ~]# 
    

    上述的lsblk命令的输出中,sr0就是附加的光盘镜像。

    在上述的虚拟机c7u6m1中挂载cdrom到/media目录下,具体如下所示:

    [root@c7u6m1 ~]# mount -t iso9660 -o loop /dev/sr0 /media/
    [root@c7u6m1 ~]# df -hT
    Filesystem           Type      Size  Used Avail Use% Mounted on
    /dev/mapper/vg0-root xfs        39G  4.9G   34G  13% /
    devtmpfs             devtmpfs  988M     0  988M   0% /dev
    tmpfs                tmpfs    1000M     0 1000M   0% /dev/shm
    tmpfs                tmpfs    1000M   25M  975M   3% /run
    tmpfs                tmpfs    1000M     0 1000M   0% /sys/fs/cgroup
    /dev/vda1            xfs       509M  129M  381M  26% /boot
    tmpfs                tmpfs     200M     0  200M   0% /run/user/0
    /dev/loop0           iso9660   4.3G  4.3G     0 100% /media
    [root@c7u6m1 ~]# ls -F /media/
    CentOS_BuildTag  EULA  images/    LiveOS/    repodata/             RPM-GPG-KEY-CentOS-Testing-7
    EFI/             GPL   isolinux/  Packages/  RPM-GPG-KEY-CentOS-7  TRANS.TBL
    [root@c7u6m1 ~]#
    

    上述就完成了对虚拟机的光盘镜像附加、挂载操作。接下来使用挂载的文件系统中的内容配置本地软件仓库。为此,需要先创建.repo格式的配置文件。

  2. 创建yum源配置文件

    在/etc/yum.repos.d目录下创建文件c7u6-local.repo,其内容如下:

    [root@c7u6m1 ~]# cat /etc/yum.repos.d/c7u6-local.repo 
    [DVD-REPO]
    name=CentOS 7.6 DVD Repository
    baseurl=file:///media
    enabled=1
    gpgcheck=1
    gpgkey=file:///media/RPM-GPG-KEY-CentOS-7
    

    由于repo配置文件的的固定格式,只需要列出上述配置文件中的字段即可。各字段含义解释如下:

    • [DVD-REPO]:指定了这个软件仓库的ID,也是后续操作的时候经常会用到的,会使用这个仓库ID来引用特定的软件仓库。注意:中括号中不能有空格
    • name=:指定了软件仓库的名称,在命令行中用不到该字段的信息,类似于对该仓库的注释、说明信息,该字段中可以有空格
    • baseurl=:指定了软件仓库的路径,如果是本地文件系统路径,则需要以file://开头,如果是网络仓库,则需要以http://或者https://开头。完整格式为baseurl=url://server1/path/to/repository
    • enabled=:可选值有两个,分别为0和1。如果为0,表示禁用该软件仓库;如果为1,表示启用该软件仓库
    • gpgcheck=:可选值有两个,分别为0和1。如果为0,则表示禁用gpg检查;如果为1,表示在安装该仓库的软件时启用gpg检查,以便确保安装的软件包的一致性和安全性
    • gpgkey=:指定gpgcheck所用的gpgkey文件的路径,使用该key文件验证所安装的该仓库中的软件包

    上述的这几个字段是最常用的字段,使用这些字段就可以完成本地软件仓库的配置工作。更多的其他字段信息以及解释,参见man yum.conf的帮助手册。

    构建完镜像仓库的配置文件之后,缓存镜像信息:

    [root@c7u6m1 ~]# vim /etc/yum.repos.d/c7u6-local.repo 
    [root@c7u6m1 ~]# yum makecache
    Loaded plugins: fastestmirror, langpacks
    Repository epel is listed more than once in the configuration
    Repository epel-debuginfo is listed more than once in the configuration
    Repository epel-source is listed more than once in the configuration
    Loading mirror speeds from cached hostfile
    DVD-REPO                   | 3.6 kB  00:00:00     
    base                       | 3.6 kB  00:00:00     
    [root@c7u6m1 media]# yum repolist
    Loaded plugins: fastestmirror, langpacks
    Repository epel is listed more than once in the configuration
    Repository epel-debuginfo is listed more than once in the configuration
    Repository epel-source is listed more than once in the configuration
    Loading mirror speeds from cached hostfile
    repo id                   repo name                    status
    DVD-REPO                  CentOS 7.6 DVD Repository    4,021
    base/7/x86_64             CentOS-7 - Base              10,072  
    

    使用配置好的本地光盘镜像安装软件:

    [root@c7u6m1 media]# yum repository-packages DVD-REPO list | egrep xz                                                                            
    Repository epel is listed more than once in the configuration
    Repository epel-debuginfo is listed more than once in the configuration
    Repository epel-source is listed more than once in the configuration
    xz-devel.x86_64                          5.2.2-1.el7                    DVD-REPO
    [root@c7u6m1 media]# yum install xz-devel
    Loaded plugins: fastestmirror, langpacks
    Repository epel is listed more than once in the configuration
    Repository epel-debuginfo is listed more than once in the configuration
    Repository epel-source is listed more than once in the configuration
    Loading mirror speeds from cached hostfile
    Resolving Dependencies
    --> Running transaction check
    ---> Package xz-devel.x86_64 0:5.2.2-1.el7 will be installed
    --> Finished Dependency Resolution
    
    Dependencies Resolved
    
    =================================================================================================================================================
     Package                           Arch                            Version                               Repository                         Size
    =================================================================================================================================================
    Installing:
     xz-devel                          x86_64                          5.2.2-1.el7                           DVD-REPO                           46 k
    
    Transaction Summary
    =================================================================================================================================================
    Install  1 Package
    
    Total download size: 46 k
    Installed size: 165 k
    Is this ok [y/d/N]: y
    Downloading packages:
    Running transaction check
    Running transaction test
    Transaction test succeeded
    Running transaction
      Installing : xz-devel-5.2.2-1.el7.x86_64         1/1 
      Verifying  : xz-devel-5.2.2-1.el7.x86_64         1/1 
    
    Installed:
      xz-devel.x86_64 0:5.2.2-1.el7                                                                                                                  
    
    Complete!
    [root@c7u6m1 media]# 
    

    上述通过安装xz-devel这个软件包,验证了配置好的软件仓库是可以正常工作的。

至此,本地仓库就构建好了,并且可以用其中的软件包通过yum命令进行软件安装操作了。

2. 编译安装

以httpd-2.4为例,进行源代码的编译安装,首先下载对应版本的源代码,然后进行编译安装,最后对于安装好的环境进行配置并验证安装效果。

2.1. 下载httpd-2.4

首先从https://mirrors.bfsu.edu.cn/apache//httpd/httpd-2.4.46.tar.bz2下载httpd-2.4的源代码压缩包。

具体如下:

[root@c7u6m1 softwares]# wget https://mirrors.bfsu.edu.cn/apache//httpd/httpd-2.4.46.tar.bz2
--2021-04-17 14:54:42--  https://mirrors.bfsu.edu.cn/apache//httpd/httpd-2.4.46.tar.bz2
Resolving mirrors.bfsu.edu.cn (mirrors.bfsu.edu.cn)... 39.155.141.16, 2001:da8:20f:4435:4adf:37ff:fe55:2840
Connecting to mirrors.bfsu.edu.cn (mirrors.bfsu.edu.cn)|39.155.141.16|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 7187805 (6.9M) [application/octet-stream]
Saving to: ‘httpd-2.4.46.tar.bz2’

100%[=======================================================================================================>] 7,187,805   9.28MB/s   in 0.7s   

2021-04-17 14:54:43 (9.28 MB/s) - ‘httpd-2.4.46.tar.bz2’ saved [7187805/7187805]

[root@c7u6m1 softwares]# ls 
httpd-2.4.46.tar.bz2
[root@c7u6m1 softwares]# ls -lh
total 6.9M
-rw-r--r-- 1 root root 6.9M Aug  5  2020 httpd-2.4.46.tar.bz2

将下载好的源码包解压缩,具体如下:

[root@c7u6m1 softwares]# tar jxvf httpd-2.4.46.tar.bz2
httpd-2.4.46/server/NWGNUmakefile
httpd-2.4.46/server/main.c
httpd-2.4.46/server/gen_test_char.mak
httpd-2.4.46/server/.indent.pro
httpd-2.4.46/server/util_expr_scan.l
httpd-2.4.46/server/provider.c
httpd-2.4.46/server/gen_test_char.dsp
httpd-2.4.46/server/Makefile.in
httpd-2.4.46/server/util_expr_private.h
httpd-2.4.46/server/mpm_common.c
httpd-2.4.46/server/util.c
httpd-2.4.46/server/util_expr_parse.h
httpd-2.4.46/server/request.c
...
[root@c7u6m1 softwares]# cd httpd-2.4.46/
[root@c7u6m1 httpd-2.4.46]# ls -F
ABOUT_APACHE     ap.d          CHANGES         docs/        httpd.spec      libhttpd.dep  Makefile.win   README            srclib/
acinclude.m4     build/        CMakeLists.txt  emacs-style  include/        libhttpd.dsp  modules/       README.cmake      support/
Apache-apr2.dsw  BuildAll.dsp  config.layout   httpd.dep    INSTALL         libhttpd.mak  NOTICE         README.platforms  test/
Apache.dsw       BuildBin.dsp  configure*      httpd.dsp    InstallBin.dsp  LICENSE       NWGNUmakefile  ROADMAP           VERSIONING
apache_probes.d  buildconf*    configure.in    httpd.mak    LAYOUT          Makefile.in   os/            server/
[root@c7u6m1 httpd-2.4.46]#

有了源代码,就可以准备编译安装了。

2.2. 编译安装

在上述的解压缩的目录中,通常会包含README以及INSTALL这两个文件,建议在编译安装之前先仔细阅读这两个文件。README是关于该源代码项目的说明信息,有时也含有安装说明。更多的时候,如何编译安装的说明,都是记录在INSTALL这个文件中。

查看INSTALL文件的内容如下所示:

[root@c7u6m1 httpd-2.4.46]# less INSTALL
Quick Start - Unix
------------------

For complete installation documentation, see [ht]docs/manual/install.html or
http://httpd.apache.org/docs/2.4/install.html

$ ./configure --prefix=PREFIX
$ make
$ make install
$ PREFIX/bin/apachectl start

上述的INSTALL文件中记录了该软件的源码编译安装所需要的命令以及启动服务的方式。其中./configure文件是可执行的,可以对安装参数进行自定义。关于支持的选项参数,可以执行命令./configure --help进行查看。其内容如下:

[root@c7u6m1 httpd-2.4.46]# ./configure --help
`configure' configures this package to adapt to many kinds of systems.

Usage: ./configure [OPTION]... [VAR=VALUE]...

To assign environment variables (e.g., CC, CFLAGS...), specify them as
VAR=VALUE.  See below for descriptions of some of the useful variables.

Defaults for the options are specified in brackets.

Configuration:
-h, --help              display this help and exit
--help=short        display options specific to this package
--help=recursive    display the short help of all the included packages
-V, --version           display version information and exit
-q, --quiet, --silent   do not print `checking ...' messages
--cache-file=FILE   cache test results in FILE [disabled]
-C, --config-cache      alias for `--cache-file=config.cache'
-n, --no-create         do not create output files
--srcdir=DIR        find the sources in DIR [configure dir or `..']

Installation directories:
--prefix=PREFIX         install architecture-independent files in PREFIX
                    [/usr/local/apache2]
--exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
                    [PREFIX]

By default, `make install' will install all the files in
`/usr/local/apache2/bin', `/usr/local/apache2/lib' etc.  You can specify
an installation prefix other than `/usr/local/apache2' using `--prefix',
for instance `--prefix=$HOME'.
...

更多的输出省略。

上述输出中,最常用的选项就是通过--prefix=/path/to/install指定该软件的安装路径。

下面选择一些基础参数进行编译安装。分为两个阶段进行介绍:

  • configure阶段

    默认情况下,执行make install之后,就是将该软件安装到/usr/local/apache2这个目录下。By default, make install will install all the files in
    /usr/local/apache2/bin, /usr/local/apache2/lib etc. You can specify
    an installation prefix other than /usr/local/apache2 using --prefix,
    for instance --prefix=$HOME.

    安装需要的基础环境包:

    [root@c7u6m1 httpd-2.4.46]# yum install -y apr apr-devel gcc gcc-c++ pcre pcre-devel pcre-static pcre-tools 
    

    安装完上述的基础环境包之后,执行.configure命令,具体如下所示:

    [root@c7u6m1 httpd-2.4.46]# ./configure --prefix=/usr/local/httpd-2.4.46
    config.status: creating build/config_vars.sh
    config.status: creating include/ap_config_auto.h
    config.status: executing default commands
    configure: summary of build options:
    
     Server Version: 2.4.46
     Install prefix: /usr/local/httpd-2.4.46
     C compiler:     gcc -std=gnu99
     CFLAGS:           -pthread  
     CPPFLAGS:        -DLINUX -D_REENTRANT -D_GNU_SOURCE  
     LDFLAGS:           
     LIBS:             
     C preprocessor: gcc -E
    [root@c7u6m1 httpd-2.4.46]# 
    [root@c7u6m1 httpd-2.4.46]# echo $?
    0
    [root@c7u6m1 httpd-2.4.46]#
    

    上述的输出中表示,./configure这个步骤正确完成。接下来进行make && make install的阶段完成安装过程。

  • make && make install阶段

    makemake install命令均可以通过-j num指定安装过程同步使用的jobs数。如果不指定-j选项,则是默认的1个。如果系统有多个核心,通常该值不超过CPU的核心数。多核编译安装比单核安装效率高。具体如下所示:

    [root@c7u6m1 httpd-2.4.46]# make -j 8 && make -j 8 install
    make[3]: Leaving directory `/root/softwares/httpd-2.4.46/modules/mappers'
    make[2]: Leaving directory `/root/softwares/httpd-2.4.46/modules'
    make[2]: Entering directory `/root/softwares/httpd-2.4.46/support'
    make[2]: Leaving directory `/root/softwares/httpd-2.4.46/support'
    
    make[1]: Leaving directory `/root/softwares/httpd-2.4.46'
    [root@c7u6m1 httpd-2.4.46]# echo $?
    0
    [root@c7u6m1 httpd-2.4.46]#
    

    上述的编译安装过程就完成了。检查下安装路径的内容,具体如下:

    [root@c7u6m1 httpd-2.4.46]# ls -F /usr/local/httpd-2.4.46/
    bin/  build/  cgi-bin/  conf/  error/  htdocs/  icons/  include/  logs/  man/  manual/  modules/
    [root@c7u6m1 httpd-2.4.46]# 
    

至此,编译安装过程就完成了。验证下是否可以访问httpd-2.4所提供的web服务。具体如下所示:

先在c7u6m1节点上启动httpd服务,具体如下:

[root@c7u6m1 bin]# ./apachectl start
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 192.168.122.2. Set the 'ServerName' directive globally to suppress this message
[root@c7u6m1 bin]# 
[root@c7u6m1 bin]# hostname c7u6m1.localhost.com
[root@c7u6m1 bin]# ./apachectl start
httpd (pid 32352) already running
[root@c7u6m1 bin]# 

上述第一次执行./apachectl start命令的时候提示主机名不是FQDN名称,所以在第4行设置了临时主机名为FQDN格式,然后再启动该httpd服务即可。

上述在服务端启动完成之后,接下来就是在客户端中执行curl命令测试到服务器端的连接:

root@ubuntu20u04:~/scripts# curl http://192.168.122.2
<html><body><h1>It works!</h1></body></html>
root@ubuntu20u04:~/scripts#

上述显示,服务端可以正常提供服务。

3. sed命令和bash环境变量内容替换、删除介绍以及示例

sed即Stream EDitor,流式编辑器。用于处理输入流、文件、或者是前一条命令的管道输出结果,执行基本的文本转换操作。其不同于交互式全屏编辑器vim,类似于脚本式的编辑器,无需进行实时交互,所以效率上也更高。sed作为流式编辑器,是以行为单位进行文本处理,即读入一行,然后对该行进行处理,完成之后将处理结果打印到标准输出;然后再读取后面的一行,并对其进行处理,完成之后将处理结果打印到标准输出;如此循环直到处理完最后一行。

在处理一行的时候,会将当前处理的行临时存储在缓冲区中,即模式空间(Pattern Space)中,随后sed会对模式空间中的内容进行处理,处理完成之后,将模式空间中的内容打印到标准输出中。接着再以相同的方式处理下一行直到文件末尾或者输入流的最后一行处理完成。由于每次只将一行内容读入到模式空间,所以对于处理很大的文件也没有压力;而vim则是将整个文件全部读入到内存中进行交互式处理,所以当文件很大的时候,打开文件的过程就会耗时不少。由于sed是类似于脚本式的行编辑器,所以其处理效率是很高的。

除了模式空间之外,sed还有一个很重要的保持空间(Hold Space),用于将模式空间的处理结果写入保持空间,而不是打印到标准输出中。加入到保持空间的内容会通过指定的命令一次全部进行输出。

3.1. sed命令基本介绍

sed命令的基本形式为sed [OPTION]... {script-only-if-no-other-script} [input-file]...,其中常用的选项如下:

  • -n:压制模式空间中的内容,使其不会自动被打印到标准输出流中
  • -e script, --expression=script:添加要执行的脚本,用于处理读入行的命令
  • -f script_file, --file=script_file:将sed的命令写入到脚本文件中,并执行这些记录在script_file中的命令
  • -r:使用拓展正则表达式
  • -i [suffix], --in-place[=suffix]:就地修改输入文件input_file,即直接对输入文件进行修改;如果指定了suffix,那么在直接修改之前会使用suffix作为后缀备份输入文件input_file

其中,script的格式为地址范围命令,即地址范围指定命令的作用域、作用范围;命令指定要执行的操作。

  • 地址范围:常见的格式有以下几种

    • 未指定地址范围:表示对全文的所有行进行处理
    • 单地址:
      • #:指定的第#行内容
      • $:输入流的最后一行
      • /pattern/:被pattern匹配到的每一行
    • 地址范围:
      • #1,#2:从#1行到#2行的内容;比如3,6表示从第3行到第6行的内容,包含第3行和第6行,意义等效于[3, 6]
      • #1,+#2:表示从#1行开始,向后增加#2行的内容;比如3,+6表示从第3行开始,往后数6行到第9行之间的内容,#2表示从第#1行开始的偏移量。同样包括第3行和第9行,意义等效于[3, 9]
      • /pat1/,/pat2/:表示从pat1匹配到的行开始,到pat2匹配到的行以及这两者之间的所有行
      • #,/pat/:表示从第#行开始到pat匹配到的行为止,第#行以及pat匹配到的行以及之间的所有行
    • 步进范围:
      • 1~2:表示处理奇数行
      • 2~2:表示处理偶数行

    更多的地址范围,参见man sed的帮助手册的Addresses部分。

  • 命令:用于处理输入行,对输入行执行的操作,常用的命令如下:

    • p:打印当前模式空间的内容,并将其追加到标准输出流中
    • Ip:忽略大小写输出
    • d:删除模式空间中被处理的行,并立即开始下一轮的循环
    • a [\]text:在指定行后面追加text指定的文本,并且支持使用\n实现换行从而实现多行追加
    • i [\]text:在指定行前面插入text指定的文本
    • c [\]text:将指定行替换为text指定的文本,text指定的文本既可以是单行,也可以是多行
    • w file:将模式空间中的内容写入到file指定的文件中
    • r file:将file指定的文件中的内容读取到模式空间中匹配的行后面
    • =:将模式空间中的内容添加行号并打印到标准输出流中
    • !:对模式空间中的匹配行进行取反处理
    • s/pattern/string/修饰符:将pattern匹配到的内容替换为string指定的内容,这两者之间的分隔符可以指定为其他单字符,比如s@pattern@string@或者s#pattern#string#,唯一需要注意的是,表达式中的分隔符需要前后一致,不能写成s@pattern#string#这种前后不一致的情况。常用的修饰符有如下几种:
      • g:行内全局搜索,即如果pattern可以在一行中进行多次匹配,那么所有这些匹配都会被替换为string指定的内容,如果不指定g,则默认是只处理第一次匹配
      • p:显示被命令处理过的行,未被命令处理过的行则不会被打印到标准输出流中
      • w /path/to/file:将被命令处理过的行写入到/path/to/file指定的文件中
      • I,i:忽略大小写,即在pattern匹配的时候,不区分大小写

除了上述sed在模式空间中的基础用法之外,还有高级用法,即将匹配的内容在模式空间(Pattern Space)与保持空间(Hold Space)之间进行相互转存,从而实现一些特定的操作。这里将会介绍常用的操作模式空间与保持空间内容切换的命令,常见命令如下所示:

  • P:将模式空间中开头到\n之间的内容插入到标准输出流之前进行打印
  • h:用模式空间中的内容覆盖保持空间中的内容
  • H:将模式空间中的内容追加到保持空间中
  • g:用保持空间中的内容覆盖模式空间中的内容
  • G:将保持空间中的内容追加到模式空间中
  • x:将模式空间中的内容与保持空间中的内容进行互换
  • n:将匹配行的下一行读取并覆盖模式空间
  • N:将匹配行的下一行读取并追加到模式空间
  • d:删除模式空间中的行
  • D:如果模式空间中包含换行符,则删除模式空间开头到第一个换行符之间的内容,并且不再读取新的输入行到模式空间中,而是使用此时模式空间的内容重新启动循环;如果模式空间中不包含换行符,此时效果等效于d命令,删除模式空间的内容,并且开始下一次匹配

更多的关于sed的命令解释,参见man sed的帮助手册的COMMAND SYNOPSIS部分的介绍。

3.2. bash变量内容替换、删除和替换

bash是支持变量内容替换的,虽然用的不多,但是在有些场景下,还是很好用的。可以通过参数扩展(Parameter Expansion)实现变量内容的删除、取代和替换等操作。

3.2.1. 变量内容的删除与替换

变量内容的删除可以分为从前往后删除,以及从后向前删除。前者用#号表示删除匹配到的最短的结果;##表示删除匹配到的最长的结果,这两个都代表从前向后删除。后者用%号表示从后向前删除匹配到的最短的结果;%%表示从后向前删除匹配到的最长的结果。

变量内容替换则使用/pattern/string表示将第一个被pattern匹配到的内容替换为string指定的内容;//pattern/string表示将变量内容中所有被pattern匹配到的内容都替换为string指定的内容。上述描述只作为表格如下所示:

动作及方向变量内容操作形式说明
最短变量内容删除,从前向后${var#pattern}将var变量中被pattern匹配到的最短内容部分删除
最长变量内容删除,从前向后${var##pattern}将var变量中被pattern匹配到的最长内容部分删除
最短变量内容删除,从后向前${var%pattern}将var变量中被pattern匹配到的最短内容部分删除
最长变量内容删除,从后向前${var%%pattern}将var变量中被pattern匹配到的最长内容部分删除
变量内容替换,仅第一个${var/pattern/string}将var变量中被pattern匹配到的第一个内容替换为string指定的内容
变量内容替换,全部${var//pattern/string}将var变量中被pattern匹配到的全部内容都替换为string指定的内容

具体示例参见下一部分的第三块内容

3.2.2. 变量测试与内容设置

可以根据被判断变量str以及表达式expr的值是否设置以及是否为空来决定最终var变量的内容。具体如下表所示:

变量内容操作形式变量str未设置时变量str为空字符串时变量str设置为非空字符串时
var=${str-expr}var=exprvar=,即也为空字符串var=$str
var=${str:-expr}var=exprvar=exprvar=$str
var=${str+expr}var=,即为空字符串var=exprvar=expr
var=${str:+expr}var=,即为空字符串var=,即为空字符串var=expr
var=${str=expr}str=expr; var=exprstr保持不变;var=,即为空字符串str保持不变;var=$str
var=${str:=expr}str=expr; var=exprstr=expr; var=exprstr保持不变;var=$str
var=${str?expr}expr打印到标准错误输出var=,即为空字符串var=$str
var=${str:?expr}expr打印到标准错误输出expr打印到标准错误输出var=$str

关于这部分的更详细的解释,参见man bash的Parameter Expansion部分的介绍。

3.3. sed命令以及变量内容删除应用示例

  1. 利用sed 取出ifconfig命令中本机的IPv4地址

    [root@c7u6m1 yum.repos.d]# ifconfig eth0 | sed -n -re 's/^[^0-9]+([0-9.]{7,15}) {1,}netmask.*/\1/p' 
    192.168.122.2
    [root@c7u6m1 yum.repos.d]#
    

    如果不加-r选项,则是无法使用上述的正则表达式的。

    -r, --regexp-extended:在脚本中使用拓展正则表达式。

  2. 删除/etc/fstab文件中所有以#开头,后面至少跟一个空白字符的行的行首的#和空白字符

    fstab文件的原始内容:

    [root@c7u6m1 tmp]# cat fstab
    
    #
    # /etc/fstab
    # Created by anaconda on Mon Dec  7 14:06:24 2020
    #
    # Accessible filesystems, by reference, are maintained under '/dev/disk'
    # See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
    #
    /dev/mapper/vg0-root    /                       xfs     defaults        0 0
    UUID=955884ac-e63e-46b1-a192-d97bef64ada9 /boot                   xfs     defaults        0 0
    UUID=257a8710-f5e9-44e4-a933-f9f6fcd0d1a3 swap                    swap    defaults        0 0
    

    使用sed命令删除#号开头且其后跟一个或者多个空白符的行开头的#号和空白符,具体如下所示:

    [root@c7u6m1 tmp]# sed -n -re ':L;s/^# {1,}([^[:blank:]]+)/\1/;H;t L;p' fstab 
    
    #
    /etc/fstab
    Created by anaconda on Mon Dec  7 14:06:24 2020
    #
    Accessible filesystems, by reference, are maintained under '/dev/disk'
    See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
    #
    /dev/mapper/vg0-root    /                       xfs     defaults        0 0
    UUID=955884ac-e63e-46b1-a192-d97bef64ada9 /boot                   xfs     defaults        0 0
    UUID=257a8710-f5e9-44e4-a933-f9f6fcd0d1a3 swap                    swap    defaults        0 0
    [root@c7u6m1 tmp]# 
    

    上述通过借助保持空间将处理的文件内容加入到保持空间中,然后通过标签label实现循环匹配处理,从而达到删除#号加多个空格开头的行中的#号以及空格的目的。

  3. 处理/etc/fstab路径,使用sed命令取出其目录名和基名

    此处使用变量删除和sed两种方式来实现。

    • 提取出目录名称,具体如下所示:

      [root@c7u6m1 tmp]# var=/etc/fstab
      [root@c7u6m1 tmp]# echo "${var%/*}"
      /etc
      [root@c7u6m1 tmp]# echo "${var%/*}/"
      /etc/
      [root@c7u6m1 tmp]#
      

      上述就提取除了给定文件路径的目录名称部分,而不包含完整路径中的文件名。

      除了用上述的变量删除的方式进行目录名称的提取之外,用sed命令方式进行提取,结果如下:

      [root@c7u6m1 tmp]# echo '/etc/fstab' | sed -n -re 's/(^\/.*\/)[^[:blank:]]+/\1/p'
      /etc/
      [root@c7u6m1 tmp]#
      

      上述即为通过变量名和sed命令进行给定绝对路径文件中的目录名称提取的两种方式,当然,系统内建了dirname这个命令可以用于实现上述效果,具体如下:

      [root@c7u6m1 tmp]# dirname '/etc/fstab' 
      /etc
      [root@c7u6m1 tmp]#
      

      上述的方式很简答, 无需像上述两种方式那样需要写那么多字符才能实现。

    • 提取出文件名称,具体如下所示:

      [root@c7u6m1 tmp]# var=/etc/fstab
      [root@c7u6m1 tmp]# echo "${var#/*/}"
      fstab
      

      上述就是用变量删除提取出了完整路径中的文件名部分,而不包含路径名称信息。

      除了使用上述的变量删除的方式进行路径中的文件名提取之外,使用sed命令提取文件名的方式如下:

      [root@c7u6m1 tmp]# echo '/etc/fstab' | sed -n -re 's/^\/[^[:blank:]]+\/([^\/]+)/\1/p'
      fstab
      [root@c7u6m1 tmp]#
      

      上述就是通过变量删除以及sed命令的方式实现的给定绝对路径文件中的文件名提取的两种方式。当然,除了上述两种复杂的实现方式之外,系统其实内建了一个命令用于实现上述目的,即basename。其结果如下所示:

      [root@c7u6m1 tmp]# basename '/etc/fstab'
      fstab
      [root@c7u6m1 tmp]# 
      

      使用系统内建命令实现的效果简单粗暴、有效。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 使用 `sed` 命令可以进行字符串替换。要替换第 N 个匹配的字符串,可以使用以下命令: ``` sed 's/要替换的字符串/替换后的字符串/N' ``` 其中,`N` 表示替换第 N 个匹配的字符串。例如,要将第 2 个匹配的字符串 "apple" 替换为 "orange",可以使用以下命令: ``` echo "I have an apple and you have an apple" | sed 's/apple/orange/2' ``` 输出结果为:`I have an apple and you have an orange`。 注意,这里的替换是在整个字符串中进行的,不是在某一行中进行的。如果你只想在某一行中替换第 N 个匹配的字符串,可以使用 `awk` 命令。 ### 回答2: sed是一种流编辑器,用于处理文本流。要使用sed匹配并替换第N个匹配项,可以使用以下命令: ```shell sed 's/匹配项/替换项/N' ``` 其中,匹配项是要被替换的文本的模式,替换项是要替换成的文本,N是指定替换第N个匹配项。 下面是一个示例,假设有一个文本文件test.txt中有多个apple出现,我们只想替换第4个apple为orange: ```shell sed 's/apple/orange/4' test.txt ``` 执行以上命令后,sed会在test.txt中找到第4个出现的apple,并将其替换为orange。如果test.txt中少于4个apple,sed不会进行替换sed命令的输出默认会直接打印在终端上。如果想要修改原始文件,可以使用-i选项,命令如下: ```shell sed -i 's/apple/orange/4' test.txt ``` 这样,替换后的结果将会保存在原始文件test.txt中。 总结一下,使用sed匹配第N个进行替换的命令格式是`sed 's/匹配项/替换项/N'`,其中匹配项是要被替换的文本的模式,替换项是要替换成的文本,N是指定替换第N个匹配项。 ### 回答3: sed命令是一种用于流编辑的Unix工具,可以实现对文本进行查找和替换的功能。虽然原生的sed命令并不直接支持匹配第N个进行替换的功能,但可以通过一些技巧来实现。 基本的sed命令语法是"s/原字符串/要替换的字符串/",其中的 "s" 表示替换操作。如果要匹配并替换第N个字符串,可以通过添加一个计数器来实现。以下是一种可能的解决方案: 1. 首先,我们需要一个能够计数的变量,可以使用awk或者其他辅助工具来实现。假设我们用变量count来计数,初始值为0。 2. 使用sed命令结合正则表达式,匹配需要替换的字符串,并在替换操作的字符串中使用"\n"表示与正则表达式匹配的内容。例如,要匹配第3个出现的字符串,并将其替换为"replacement",可以使用如下命令: sed ':a;N;$!ba;s/regexp/replacement/3' 其中,regexp表示正则表达式,replacement表示替换成的字符串,3表示需要匹配的第3个字符串。 3. 将输出重定向到文件中,即将替换后的结果保存下来,可以使用">"命令将sed命令的输出重定向到指定文件中。 虽然这个方法需要稍微复杂一些,但是可以通过使用变量和一些sed命令的技巧来实现匹配第N个字符串进行替换的功能。 需要注意的是,此方法只适用于替换单个文件中的第N个字符串。如果要替换多个文件,可以使用循环结构和适当的文件名模式来批量替换

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值