Merge remote-tracking branch 'LCTT/master'

This commit is contained in:
Xingyu.Wang 2018-11-12 23:32:20 +08:00
commit 5a71794449
5 changed files with 268 additions and 298 deletions

View File

@ -1,13 +1,16 @@
Bash脚本中如何使用 here 文档将数据写入文件
Bash 脚本中如何使用 here 文档将数据写入文件
======
<ruby>here 文档<rt>here document</rt></ruby> LCTT译注here文档又称作 heredoc )不是什么特殊的东西,只是一种 I/O 重定向方式它告诉bash shell从当前源读取输入直到读取到只有分隔符的行。
![redirect output of here document to a text file][1]
这对于向 ftpcatechossh 和许多其他有用的 Linux/Unix 命令提供指令很有用。 此功能适用于 bash也适用于 BourneKornPOSIX 这三种 shell。
<ruby>here 文档<rt>here document</rt></ruby> LCTT 译注here 文档又称作 heredoc )不是什么特殊的东西,只是一种 I/O 重定向方式,它告诉 bash shell 从当前源读取输入,直到读取到只有分隔符的行。
## here 文档语法
![redirect output of here document to a text file][1]
这对于向 ftp、cat、echo、ssh 和许多其他有用的 Linux/Unix 命令提供指令很有用。 此功能适用于 bash 也适用于 Bourne、Korn、POSIX 这三种 shell。
### here 文档语法
语法是:
```
command <<EOF
cmd1
@ -15,17 +18,18 @@ cmd2 arg1
EOF
```
或者允许shell脚本中的 here 文档使用 **EOF<<-** 以自然的方式缩进
或者允许 shell 脚本中的 here 文档使用 `EOF<<-` 以自然的方式缩进:
```
command <<-EOF
msg1
msg2
$var on line
msg1
msg2
$var on line
EOF
```
或者
```
command <<'EOF'
cmd1
@ -35,9 +39,10 @@ command <<'EOF'
EOF
```
或者 **重定向并将其覆盖** 到名为my_output_file.txt的文件中
或者 **重定向并将其覆盖** 到名为 `my_output_file.txt` 的文件中:
```
command << EOF > my_output_file.txt
command <<EOF > my_output_file.txt
mesg1
msg2
msg3
@ -45,10 +50,10 @@ command << EOF > my_output_file.txt
EOF
```
或**重定向并将其追加**到名为my_output_file.txt的文件中
或**重定向并将其追加**到名为 `my_output_file.txt` 的文件中:
```
command << EOF >> my_output_file.txt
command <<EOF >> my_output_file.txt
mesg1
msg2
msg3
@ -56,9 +61,9 @@ command << EOF >> my_output_file.txt
EOF
```
## 示例
### 示例
以下脚本将所需内容写入名为/tmp/output.txt的文件中
以下脚本将所需内容写入名为 `/tmp/output.txt` 的文件中:
```
#!/bin/bash
@ -86,12 +91,11 @@ $ cat /tmp/output.txt
```
Status of backup as on Thu Nov 16 17:00:21 IST 2017
Backing up files /home/vivek and /etc/
```
### 禁用路径名/参数/变量扩展,命令替换,算术扩展
### 禁用路径名/参数/变量扩展、命令替换、算术扩展
像 $HOME 这类变量和像 $(date) 这类命令在脚本中会被解释为替换。 要禁用它,请使用带有 'EOF' 这样带有单引号的形式,如下所示:
`$HOME` 这类变量和像 `$(date)` 这类命令在脚本中会被解释为替换。 要禁用它,请使用带有 `'EOF'` 这样带有单引号的形式,如下所示:
```
#!/bin/bash
@ -110,7 +114,7 @@ EOF
echo "Starting backup using rsync..."
```
你可以使用[cat命令][3]查看/tmp/output.txt文件
你可以使用 [cat 命令][3]查看 `/tmp/output.txt` 文件:
```
$ cat /tmp/output.txt
@ -124,9 +128,10 @@ $ cat /tmp/output.txt
```
## 关于 tee 命令的使用
### 关于 tee 命令的使用
语法是:
```
tee /tmp/filename <<EOF >/dev/null
line 1
@ -137,7 +142,7 @@ $var on $foo
EOF
```
或者通过在单引号中引用EOF来禁用变量替换和命令替换
或者通过在单引号中引用 `EOF` 来禁用变量替换和命令替换:
```
tee /tmp/filename <<'EOF' >/dev/null
@ -150,6 +155,7 @@ EOF
```
这是我更新的脚本:
```
#!/bin/bash
OUT=/tmp/output.txt
@ -165,9 +171,10 @@ EOF
echo "Starting backup using rsync..."
```
## 关于内存 here 文档的使用
### 关于内存 here 文档的使用
这是我更新的脚本:
```
#!/bin/bash
OUT=/tmp/output.txt
@ -189,19 +196,17 @@ cat <&9 >$OUT
echo "Starting backup using rsync..."
```
--------------------------------------------------------------------------------
via: https://www.cyberciti.biz/faq/using-heredoc-rediection-in-bash-shell-script-to-write-to-file/
作者:[Vivek Gite][a]
译者:[Flowsnow](https://github.com/Flowsnow)
校对:[校对者ID](https://github.com/校对者ID)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://www.cyberciti.biz
[1]: https://www.cyberciti.biz/media/new/faq/2017/11/redirect-output-of-here-document-to-a-text-file.jpg
[2]: https://bash.cyberciti.biz/guide/Here_documents
[3]: https//www.cyberciti.biz/faq/linux-unix-appleosx-bsd-cat-command-examples/ "See Linux/Unix cat command examples for more info"
[3]: https//www.cyberciti.biz/faq/linux-unix-appleosx-bsd-cat-command-examples/

View File

@ -1,128 +0,0 @@
fuowang 翻译中
Using Your Own Private Registry with Docker Enterprise Edition
======
![docker trusted registry][1]
One of the things that makes Docker really cool, particularly compared to using virtual machines, is how easy it is to move around Docker images. If you've already been using Docker, you've almost certainly pulled images from [Docker Hub][2]. Docker Hub is Docker's cloud-based registry service and has tens of thousands of Docker images to choose from. If you're developing your own software and creating your own Docker images though, you'll want your own private Docker registry. This is particularly true if you have images with proprietary licenses, or if you have a complex continuous integration (CI) process for your build system.
Docker Enterprise Edition includes Docker Trusted Registry (DTR), a highly available registry with secure image management capabilities which was built to run either inside of your own data center or on your own cloud-based infrastructure. In the next few weeks, we'll go over how DTR is a critical component of delivering a secure, repeatable and consistent [software supply chain][3]. You can get started with it today through our [free hosted demo][4] or by downloading and installing the free 30-day trial. The steps to get started with your own installation are below.
## Setting Up Docker Enterprise Edition
Docker Trusted Registry runs on top of Universal Control Plane (UCP), so to begin let's install a single-node cluster. If you've already got your own UCP cluster, you can skip this step. On your docker host, run the command:
```
# Pull and install UCP
docker run -it -rm -v /var/run/docker.sock:/var/run/docker.sock -name ucp docker/ucp:latest install
```
Once UCP is up and running, there are a few more things you should do before you install DTR. Open up your browser against the UCP instance you just installed. There should be a link to it at the end of your log output. If you have already have a Docker Enterprise Edition license, go ahead and upload it through the UI. If you don't, visit the [Docker Store][5] and pick up a free, 30-day trial.
Once you've got licensing squared away, you're probably going to want to change the port which UCP is running on. Since this is a single node cluster, DTR and UCP are going to want to use the same TCP ports for running their web services. If you've got a UCP swarm with more than one node, this probably isn't a problem because DTR will look for a node which has the required free ports. Inside of UCP, click on Admin Settings -> Cluster Configuration and change the Controller Port to something like 5443.
## Installing DTR
We're going to install a simple, single-node instance of Docker Trusted Registry. If you were setting up your DTR for production use, you would likely set things up in High Availability (HA) mode which would require a different type of storage such as a cloud-based object store, or NFS. Since this is a single-node instance, we're going to stick with the default local storage.
First we need to pull the DTR bootstrap image. The bootstrap image is a tiny, self-contained installer which connects to UCP and sets up all of the containers, volumes, and logical networks required to get DTR up and running.
Use the command:
```
# Pull and run the DTR bootstrapper
docker run -it -rm docker/dtr:latest install -ucp-insecure-tls
```
NOTE: Both UCP and DTR by default come with their own certs which won't be recognized by your system. If you've set up UCP with TLS certs which are trusted by your system, you can omit the `-ucp-insecure-tls` option. Alternatively, you can use the `-ucp-ca` option which will let you specify the UCP CA certificate directly.
The DTR bootstrap image should then ask you for a couple of settings, such as the URL of your UCP installation and your UCP admin username and password. It should only take a minute or two to pull all of the DTR images and set everything up.
## Keeping Everything Secure
Once everything is up and running, you're ready to push and pull images to and from
the registry. Before we do that step though, let's set up our TLS certificates so that we can securely talk to DTR.
On Linux, we can use these commands (just make certain you change DTR_HOSTNAME to reflect the DTR we just set up):
```
# Pull the CA certificate from DTR (you can use wget if curl is unavailable)
DTR_HOSTNAME=<Your DTR hostname>
curl -k https://$(DTR_HOSTNAME)/ca > $(DTR_HOSTNAME).crt
sudo mkdir /etc/docker/certs.d/$(DTR_HOSTNAME)
sudo cp $(DTR_HOSTNAME) /etc/docker/certs.d/$(DTR_HOSTNAME)
# Restart the docker daemon (use `sudo service docker restart` on Ubuntu 14.04)
sudo systemctl restart docker
```
On Docker for Mac and Windows, we'll set up our client a little bit differently. Go in to Settings -> Daemon and in the Insecure Registries section, enter in your DTR hostname. Click Apply, and your docker daemon should restart and you should be good to go.
## Pushing and Pulling Images
We now need to set up a repository to hold an image. This is a little bit different than Docker Hub which automatically creates a repository if one doesn't exist when you do a docker push. To create the repository, point your browser to https://<Your DTR hostname> and then sign-in with your admin credentials when prompted. If you added a license to UCP, that license will automatically have been picked up by DTR. If not, make certain you upload your license now.
Once you're in, click on the 'New Repository` button and create a new repository.
We'll create a repo to hold Alpine linux, so type `alpine` in the name field, and click
`Save` (it's labelled `Create` in DTR 2.5 and newer).
Now let's go back to our shell and type the commands:
```
# Pull the latest version of Alpine Linux
docker pull alpine:latest
# Sign in to your new DTR instance
docker login <Your DTR hostname>
# Tag Alpine to be able to push it to your DTR
docker tag alpine:latest <Your DTR hostname>/admin/alpine:latest
# Push the image to DTR
docker push <Your DTR hostname>/admin/alpine:latest
```
And that's it! We just pulled a copy of the latest Alpine Linux, re-tagged it so that we could store it inside of DTR, and then pushed it to our private registry. If you want to pull that image to a different Docker engine, set up your DTR certs as shown above, and issue the command:
```
# Pull the image from DTR
docker pull <Your DTR hostname>/admin/alpine:latest
```
DTR has a lot of great image management features built right in such as image caching, mirroring, scanning, signing, and even automated supply chain policies. We'll leave these to future blog posts which we can explore in more detail.
--------------------------------------------------------------------------------
via: https://blog.docker.com/2018/01/dtr/
作者:[Patrick Devine;Rolf Neugebauer;Docker Core Engineering;Matt Bentley][a]
译者:[译者ID](https://github.com/译者ID)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://blog.docker.com/author/pdevine/
[1]:https://i1.wp.com/blog.docker.com/wp-content/uploads/ccd278d2-29c2-4866-8285-c2fe60b4bd5e-1.jpg?resize=965%2C452&ssl=1
[2]:https://hub.docker.com/
[3]:https://blog.docker.com/2016/08/securing-enterprise-software-supply-chain-using-docker/
[4]:https://www.docker.com/trial
[5]:https://store.docker.com/search?offering=enterprise&page=1&q=&type=edition

View File

@ -1,3 +1,5 @@
HankChow translating
An Overview of Android Pie
======

View File

@ -0,0 +1,122 @@
使用企业版 Docker 搭建自己的私有注册服务器
======
![docker trusted registry][1]
Docker 真的很酷,特别是和使用虚拟机相比,转移 Docker 镜像十分容易。如果你已准备好使用 Docker那你肯定已从 [Docker Hub][2] 上拉取完整的镜像。Docker Hub 是 Docker 的云端注册服务器服务,包含成千上万个供选择的 Docker 镜像。如果你开发了自己的软件包并创建了自己的 Docker 镜像那么你会想有自己的私有注册服务器。如果你有搭配着专有许可的镜像或想为你的构建系统提供复杂的持续集成CI过程则更应该拥有自己的私有注册服务器。
Docker 企业版包括 Docker Trusted Registry译者注DTRDocker 可信注册服务器)。这是一个具有安全镜像管理功能的高可用的注册服务器,为了在你自己的数据中心或基于云端的架构上运行而构建。在接下来的几周,我们将了解 DTR 是提供安全、可重用且连续的[软件供应链][3]的一个关键组件。你可以通过我们的[免费托管小样][4]立即开始使用,或者通过下载安装进行 30 天的免费试用。下面是开始自己安装的步骤。
## 配置 Docker 企业版
Docker Trusted Registry 在通用控制面板UCP上运行所以开始前要安装一个单节点集群。如果你已经有了自己的 UCP 集群,可以跳过这一步。在你的 docker 托管主机上,运行以下命令:
```
# 拉取并安装 UCP
docker run -it -rm -v /var/run/docker.sock:/var/run/docker.sock -name ucp docker/ucp:latest install
```
当 UCP 启动并运行后,在安装 DTR 之前你还有几件事要做。针对刚刚安装的 UCP 实例,打开浏览器。在日志输出的末尾应该有一个链接。如果你已经有了 Docker 企业版的许可证,那就在这个界面上输入它吧。如果你还没有,可以访问 [Docker 商店][5]获取30天的免费试用版。
准备好许可证后,你可能会需要改变一下 UCP 运行的端口。因为这是一个单节点集群DTR 和 UCP 可能会以相同的端口运行他们的 web 服务。如果你拥有不只一个节点的 UCP 集群,这就不是问题,因为 DTR 会寻找有所需空闲端口的节点。在 UCP 中,点击管理员设置 -> 集群配置并修改控制器端口,比如 5443。
## 安装 DTR
我们要安装一个简单的、单节点的 Docker Trusted Registry 实例。如果你要安装实际生产用途的 DTR那么你会将其设置为高可用HA模式即需要另一种存储介质比如基于云端的对象存储或者 NFS译者注Network File System网络文件系统。因为目前安装的是一个单节点实例我们依然使用默认的本地存储。
首先我们需要拉取 DTR 的 bootstrap 镜像。Boostrap 镜像是一个微小的独立安装程序,包括连接到 UCP 以及设置和启动 DTR 所需的所有容器、卷和逻辑网络。
使用命令:
```
# 拉取并运行 DTR 引导程序
docker run -it -rm docker/dtr:latest install -ucp-insecure-tls
```
注意默认情况下UCP 和 DTR 都有自己的证书,系统无法识别。如果你已使用系统信任的 TLS 证书设置 UCP则可以省略 `-ucp-insecure-tls` 选项。另外,你可以使用 `-ucp-ca` 选项来直接指定 UCP 的 CA 证书。
然后 DTR bootstrap 镜像会让你确定几项设置,比如 UCP 安装的 URL 地址以及管理员的用户名和密码。从拉取所有的 DTR 镜像到设置全部完成,只需要一到两分钟的时间。
## 保证一切安全
一切都准备好后,就可以向注册服务器推送或者从中拉取镜像了。在做这一步之前,让我们设置 TLS 证书,以便安全的与 DTR 通信。
在 Linux 上,我们可以使用以下命令(只需确保更改了 DTR_HOSTNAME 变量,来正确映射我们刚刚设置的 DTR
```
# 从 DTR 拉取 CA 证书(如果 curl 不可用,你可以使用 wget
DTR_HOSTNAME=< DTR 主机名>
curl -k https://$(DTR_HOSTNAME)/ca > $(DTR_HOSTNAME).crt
sudo mkdir /etc/docker/certs.d/$(DTR_HOSTNAME)
sudo cp $(DTR_HOSTNAME) /etc/docker/certs.d/$(DTR_HOSTNAME)
# 重启 docker 守护进程(在 Ubuntu 14.04 上,使用 `sudo service docker restart` 命令)
sudo systemctl restart docker
```
对于 Mac 和 Windows 版的 Docker我们会以不同的方式安装客户端。转入设置 -> 守护进程,在 Insecure Registries译者注不安全的注册服务器部分输入你的 DTR 主机名。点击应用docker 守护进程应在重启后可以良好使用。
## 推送和拉取镜像
现在我们需要设置一个仓库来存放镜像。这和 Docker Hub 有一点不同,如果你做的 docker 推送仓库中不存在,它会自动创建一个。要创建一个仓库,在浏览器中打开 https://<Your DTR hostname> 并在出现登录提示时使用你的管理员凭据登录。如果你向 UCP 添加了许可证,则 DTR 会自动获取该许可证。如果没有,请现在确认上传你的许可证。
进入刚才的网页之后,点击`新建仓库`按钮来创建新的仓库。
我们会创建一个用于存储 Alpine linux 的仓库,所以在名字输入处键入 `alpine`,点击`保存`(在 DTR 2.5 及更高版本中叫`创建`)。
现在我们回到 shell 界面输入以下命令:
```
# 拉取 Alpine Linux 的最新版
docker pull alpine:latest
# 登入新的 DTR 实例
docker login <Your DTR hostname>
# 标记上 Alpine 使能推送其至你的 DTR
docker tag alpine:latest <Your DTR hostname>/admin/alpine:latest
# 向 DTR 推送镜像
docker push <Your DTR hostname>/admin/alpine:latest
```
就是这样!我们刚刚推送了最新的 Alpine Linux 的一份拷贝,重新打了标签以便将其存储到 DTR 中,并将其推送到我们的私有注册服务器。如果你想将镜像拉取至不同的 Docker 引擎中,按如上所示设置你的 DTR 证书,然后执行以下命令:
```
# 从 DTR 中拉取镜像
docker pull <Your DTR hostname>/admin/alpine:latest
```
DTR 具有许多优秀的镜像管理功能,例如图像缓存,镜像,扫描,签名甚至自动化供应链策略。这些功能我们在后期的博客文章中更详细的探讨。
--------------------------------------------------------------------------------
via: https://blog.docker.com/2018/01/dtr/
作者:[Patrick Devine;Rolf Neugebauer;Docker Core Engineering;Matt Bentley][a]
译者:[fuowang](https://github.com/fuowang)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://blog.docker.com/author/pdevine/
[1]:https://i1.wp.com/blog.docker.com/wp-content/uploads/ccd278d2-29c2-4866-8285-c2fe60b4bd5e-1.jpg?resize=965%2C452&ssl=1
[2]:https://hub.docker.com/
[3]:https://blog.docker.com/2016/08/securing-enterprise-software-supply-chain-using-docker/
[4]:https://www.docker.com/trial
[5]:https://store.docker.com/search?offering=enterprise&page=1&q=&type=edition

View File

@ -271,7 +271,7 @@ Sed 允许在一个块中使用花括号 `{…}` 组合命令。你可以利用
```
sed -n -e '/usb/{
/daemon/p
/daemon/p
}' inputfile
sed -n -e '/usb.*daemon/p' inputfile
@ -311,8 +311,8 @@ sed -e '5q' inputfile
sed -n -e '5p' -e '5q' inputfile
sed -n -e '
5p
5q
5p
5q
' inputfile
sed -n -e '5p;5q' inputfile
@ -323,8 +323,8 @@ sed -n -e '5p;5q' inputfile
```
# 组合命令
sed -e '5{
p
q
p
q
}' inputfile
# 可以简写为:
@ -336,272 +336,241 @@ sed '5{p;q}' inputfile
### 替换命令
你可以将替换命令想像为 Sed 的“查找替换”功能这个功能在大多数的“所见即所得”的编辑器上都能找到。Sed 的替换命令与之类似,但比它们更强大。替换命令是 Sed 中最著名的命令之一,在网上有大量的关于这个命令的文档。
你可以将替换命令`s`想像为 Sed 的“查找替换”功能这个功能在大多数的“所见即所得”的编辑器上都能找到。Sed 的替换命令与之类似,但比它们更强大。替换命令是 Sed 中最著名的命令之一,在网上有大量的关于这个命令的文档。
![The Sed `substitution` command][19]
[在前一篇文章][20]中我们已经讲过它了,因此,在这里就不再重复了。但是,如果你对它的使用不是很熟悉,那么你需要记住下面的这些关键点:
* 替换命令有两个参数:查找模式和替换字符串:`sed s/:/-----/ inputfile`
* 命令和它的参数是用任意一个字符来分隔的。这主要看你的习惯,在 99% 的时间中我都使用斜杠,但也会用其它的字符:`sed s%:%-----% inputfile`、`sed sX:X-----X inputfile` 或者甚至是 `sed 's : ----- ' inputfile`
* 默认情况下,替换命令仅被应用到模式空间中匹配到的第一个字符串上。你可以通过在命令之后指定一个匹配指数作为标志来改变这种情况:`sed 's/:/-----/1' inputfile`、`sed 's/:/-----/2' inputfile`、`sed 's/:/-----/3' inputfile`、…
* 如果你想执行一个全面的替换(即:在模式空间上的每个非重叠匹配),你需要增加 `g` 标志:`sed 's/:/-----/g' inputfile`
* 在字符串替换中,出现的任何一个 `&` 符号都将被与查找模式匹配的子字符串替换:`sed 's/:/-&&&-/g' inputfile`、`sed 's/…./& /g' inputfile`
* 圆括号(在扩展的正则表达式中的 `(…)` 或者基本的正则表达式中的 `\(…\)`)被引用为捕获组。那是匹配字符串的一部分,可以在替换字符串中被引用。`\1` 是第一个捕获组的内容,`\2` 是第二个捕获组的内容,依次类推:`sed -E 's/(.)(.)/\2\1/g' inputfile`、`sed -E 's/(.):x:(.):(.*)/\1:\3/' inputfile`(后者之所能正常工作是因为 [正则表达式中的量词星号表示重复匹配下去,直到不匹配为止][21],并且它可以匹配许多个字符)
* 在查找模式或替换字符串时,你可以通过使用一个反斜杠来去除任何字符的特殊意义:`sed 's/:/--\&--/g' inputfile``sed 's/\//\\/g' inputfile`
* 替换命令有两个参数:查找模式和替换字符串:`sed s/:/-----/ inputfile`
* `s` 命令和它的参数是用任意一个字符来分隔的。这主要看你的习惯,在 99% 的时间中我都使用斜杠,但也会用其它的字符:`sed s%:%-----% inputfile`、`sed sX:X-----X inputfile` 或者甚至是 `sed 's : ----- ' inputfile`
* 默认情况下,替换命令仅被应用到模式空间中匹配到的第一个字符串上。你可以通过在命令之后指定一个匹配指数作为标志来改变这种情况:`sed 's/:/-----/1' inputfile`、`sed 's/:/-----/2' inputfile`、`sed 's/:/-----/3' inputfile`、…
* 如果你想执行一个全局替换(即:在模式空间上的每个非重叠匹配上进行),你需要增加 `g` 标志:`sed 's/:/-----/g' inputfile`
* 在字符串替换中,出现的任何一个 `&` 符号都将被与查找模式匹配的子字符串替换:`sed 's/:/-&&&-/g' inputfile`、`sed 's/.../& /g' inputfile`
* 圆括号(在扩展的正则表达式中的 `(...)` ,或者基本的正则表达式中的 `\(...\)`)被当做<ruby>捕获组<rt>capturing group</rt></ruby>。那是匹配字符串的一部分,可以在替换字符串中被引用。`\1` 是第一个捕获组的内容,`\2` 是第二个捕获组的内容,依次类推:`sed -E 's/(.)(.)/\2\1/g' inputfile`、`sed -E 's/(.):x:(.):(.*)/\1:\3/' inputfile`(后者之所能正常工作是因为 [正则表达式中的量词星号表示尽可能多的匹配,直到不匹配为止][21],并且它可以匹配许多个字符)
* 在查找模式或替换字符串时,你可以通过使用一个反斜杠来去除任何字符的特殊意义:`sed 's/:/--\&--/g' inputfile``sed 's/\//\\/g' inputfile`
所有的这些看起来有点抽象,下面是一些示例。首先,我想去显示我的测试输入文件的第一个字段并给它在右侧附加 20 个空格字符,我可以这样写:
```
sed < inputfile -E -e '
s/:/ / # 用 20 个空格替换第一个字段的分隔符
s/(.{20}).*/\1/ # 只保留一行的前 20 个字符
s/.*/| & |/ # 为了输出好看添加竖条
s/:/ / # 用 20 个空格替换第一个字段的分隔符
s/(.{20}).*/\1/ # 只保留一行的前 20 个字符
s/.*/| & |/ # 为了输出好看添加竖条
'
```
第二个示例是,如果我想将用户 sonia 的 UID/GID 修改为 1100我可以这样写
```
sed -En -e '
/sonia/{
s/[0-9]+/1100/g
p
/sonia/{
s/[0-9]+/1100/g
p
}' inputfile
```
注意在替换命令结束部分的 `g` 选项。这个选项改变了它的行为,因此它将查找全部的模式空间并替换,如果没有那个选项,它只替换查找到的第一个。
顺便说一下,这也是使用前面讲过的输出(`p`)命令的好机会,可以在命令运行时输出修改前后时刻模式空间的内容。因此,为了获得替换前后的内容,我可以这样写:
顺便说一下,这也是使用前面讲过的输出(`p`)命令的好机会,可以在命令运行时输出修改前后的模式空间的内容。因此,为了获得替换前后的内容,我可以这样写:
```
sed -En -e '
/sonia/{
p
s/[0-9]+/1100/g
p
/sonia/{
p
s/[0-9]+/1100/g
p
}' inputfile
```
事实上,替换后输出一个行是很常见的用法,因此,替换命令也接受 `p` 选项:
```
sed -En -e '/sonia/s/[0-9]+/1100/gp' inputfile
```
最后,我就不详细讲替换命令的 `w` 选项了,我们将在稍后的学习中详细介绍。
#### delete 命令
### 删除命令
删除命令(`d`用于清除模式空间的内容然后立即开始下一个处理循环。这样它将会跳过隐式输出模式空间内容的行为即便是你设置了自动输出标志AP也不会输出。
![The Sed `delete` command][22]
只输出一个文件前五行的一个很低效率的方法将是:
```
sed -e '6,$d' inputfile
```
你猜猜看,我为什么说它很低效率?如果你猜不到,建议你再次去阅读前面的关于 quit 命令的章节,答案就在那里!
你猜猜看,我为什么说它很低效率?如果你猜不到,建议你再次去阅读前面的关于退出命令的章节,答案就在那里!
当你组合使用正则表达式和地址,从输出中删除匹配的行时,删除命令将非常有用:
当你组合使用正则表达式和地址从输出中删除匹配的行时delete 命令将非常有用:
```
sed -e '/systemd/d' inputfile
```
#### next 命令
### 次行命令
如果 Sed 命令不是在静默模式中运行,这个命令将输出当前模式空间的内容,然后,在任何情况下它将读取下一个输入行到模式空间中,并使用新的模式空间中的内容来运行当前循环中剩余的命令。
如果 Sed 命令没有运行在静默模式中,这个命令(`n`将输出当前模式空间的内容,然后,在任何情况下它将读取下一个输入行到模式空间中,并使用新的模式空间中的内容来运行当前循环中剩余的命令。
![The Sed `next` command][23]
![The Sed next command][23]
用次行命令去跳过行的一个常见示例:
常见的用 next 命令去跳过行的一个示例:
```
cat -n inputfile | sed -n -e 'n;n;p'
```
在上面的例子中Sed 将隐式地读取输入文件的第一行。但是 `next` 命令将丢弃对模式空间中的内容的输出(不输出是因为使用了 `-n` 选项),并从输入文件中读取下一行来替换模式空间中的内容。而第二个 `next` 命令做的事情和前一个是一模一样的,这就实现了跳过输入文件 2 行的目的。最后,这个脚本显式地输出包含在 `pattern ` 空间中的输入文件的第三行的内容。然后Sed 将启动一个新的循环,由于 `next` 命令,它会隐式地读取第 4 行的内容,然后跳过它,同样地也跳过第 5 行,并输出第 6 行。如此循环,直到文件结束。总体来看,这个脚本就是读取输入文件然后每三行输出一行。
在上面的例子中Sed 将隐式地读取输入文件的第一行。但是次行命令将丢弃对模式空间中的内容的输出(不输出是因为使用了 `-n` 选项),并从输入文件中读取下一行来替换模式空间中的内容。而第二个次行命令做的事情和前一个是一模一样的,这就实现了跳过输入文件 2 行的目的。最后这个脚本显式地输出包含在模式空间中的输入文件的第三行的内容。然后Sed 将启动一个新的循环,由于次行命令,它会隐式地读取第 4 行的内容,然后跳过它,同样地也跳过第 5 行,并输出第 6 行。如此循环,直到文件结束。总体来看,这个脚本就是读取输入文件然后每三行输出一行。
使用次行命令,我们也可以找到一些显示输入文件的前五行的几种方法:
使用 next 命令,我们也可以找到一些显示输入文件的前五行的几种方法:
```
cat -n inputfile | sed -n -e '1{p;n;p;n;p;n;p;n;p}'
cat -n inputfile | sed -n -e 'p;n;p;n;p;n;p;n;p;q'
cat -n inputfile | sed -e 'n;n;n;n;q'
```
更有趣的是如果你需要根据一些地址来处理行时next 命令也非常有用:
```
cat -n inputfile | sed -n '/pulse/p' # 输出包含 "pulse" 的行
cat -n inputfile | sed -n '/pulse/{n;p}' # 输出包含 "pulse" 之后的行
cat -n inputfile | sed -n '/pulse/{n;n;p}' # 输出下面的行
# 下一行
# 包含 "pulse" 的行
更有趣的是,如果你需要根据一些地址来处理行时,次行命令也非常有用:
```
cat -n inputfile | sed -n '/pulse/p' # 输出包含 “pulse” 的行
cat -n inputfile | sed -n '/pulse/{n;p}' # 输出包含 “pulse” 之后的行
cat -n inputfile | sed -n '/pulse/{n;n;p}' # 输出包含 “pulse” 的行的下一行的下一行
```
### 使用保持空间
到目前为止,我们所看到的命令都是仅使用了模式空间。但是,我们在文章的开始部分已经提到过,还有第二个缓冲区:保持空间,它完全由用户管理。它就是我们在第二节中描述的目标。
#### exchange 命令
#### 交换命令
正如它的名字所表示的,exchange 命令(`x`)将交换保持空间和模式空间的内容。记住,你只要没有把任何东西放入到保持空间中,那么保持空间就是空的。
正如它的名字所表示的,交换命令(`x`)将交换保持空间和模式空间的内容。记住,你只要没有把任何东西放入到保持空间中,那么保持空间就是空的。
![The Sed `exchange` command][24]
![The Sed exchange command][24]
作为第一个示例,我们可使用交换命令去反序输出一个输入文件的前两行:
作为第一个示例,我们可使用 exchange 命令去反序输出一个输入文件的前两行:
```
cat -n inputfile | sed -n -e 'x;n;p;x;p;q'
```
当然,在你设置 `hold` 之后你并没有立即使用它的内容,因为只要你没有显式地去修改它,保持空间中的内容就保持不变。在下面的例子中,我在输入一个文件的前五行后,使用它去删除第一行:
当然,在你设置保持空间之后你并没有立即使用它的内容,因为只要你没有显式地去修改它,保持空间中的内容就保持不变。在下面的例子中,我在输入一个文件的前五行后,使用它去删除第一行:
```
cat -n inputfile | sed -n -e '
1{x;n} # 交换 hold 和 pattern 空间
# 保存第 1 行到 hold 空间中
# 然后读取第 2 行
1{x;n} # 交换保持和模式空间
# 保存第 1 行到保持空间中
# 然后读取第 2 行
5{
p # 输出第 5 行
x # 交换 hold 和 pattern 空间
# 去取得第 1 行的内容放回到
# pattern 空间
p # 输出第 5 行
x # 交换保持和模式空间
# 去取得第 1 行的内容放回到模式空间
}
1,5p # 输出第 2 到第 5 行
# (不要输错了!尝试找出这个规则
# 没有在第 1 行上运行的原因;)
1,5p # 输出第 2 到第 5 行
# (并没有输错!尝试找出这个规则
# 没有在第 1 行上运行的原因 ;)
'
```
#### hold 命令
#### 保持命令
hold 命令(`h`)是用于将模式空间中的内容保存到保持空间中。但是,与 exchange 命令不同的是模式空间中的内容不会被改变。hold 命令有两种用法:
保持命令(`h`)是用于将模式空间中的内容保存到保持空间中。但是,与交换命令不同的是,模式空间中的内容不会被改变。保持命令有两种用法:
* `h`
将复制模式空间中的内容到保持空间中,将覆盖保持空间中任何已经存在的内容
* `h` 将复制模式空间中的内容到保持空间中,覆盖保持空间中任何已经存在的内容。
* `H` 将模式空间中的内容追加到保持空间中,使用一个新行作为分隔符
* `H`
使用一个独立的新行,追加模式空间中的内容到保持空间中。
![The Sed hold command][25]
上面使用交换命令的例子可以使用保持命令重写如下:
![The Sed `hold` command][25]
上面使用 exchange 命令的例子可以使用 hold 命令重写如下:
```
cat -n inputfile | sed -n -e '
1{h;n} # 保存第 1 行的内容到 hold 缓冲区并继续
5{ # 到第 5 行
x # 交换 pattern 和 hold 空间
# (现在 pattern 空间包含了第 1 行)
H # 在 hold 空间的第 5 行后追回第 1 行
x # 再次交换取回第 5 行并将第 1 行插入
# 到 pattern 空间
1{h;n} # 保存第 1 行的内容到保持缓冲区并继续
5{ # 在第 5 行
x # 交换模式和保持空间
# (现在模式空间包含了第 1 行)
H # 在保持空间的第 5 行后追加第 1 行
x # 再次交换第 5 行和第 1 行,第 5 行回到模式空间
}
1,5p # 输出第 2 行到第 5 行
# (不要输错!尝试去打到为什么这个规则
# 不在第 1 行上运行;)
1,5p # 输出第 2 行到第 5 行
# (没有输错!尝试去找到为什么这个规则
# 不在第 1 行上运行 ;)
'
```
#### get 命令
#### 获取命令
get 命令(`g`)与 hold 命令恰好相反:它从保持空间中取得内容并将它置入到模式空间中。同样它也有两种方式:
获取命令(`g`)与保持命令恰好相反:它从保持空间中取得内容并将它置入到模式空间中。同样它也有两种方式:
* `g`
它将复制保持空间中的内容并将其放入到模式空间,覆盖 `pattern`空间中已存在的任何内容
* `g` 将复制保持空间中的内容并将其放入到模式空间,覆盖模式空间中已存在的任何内容
* `G` 将保持空间中的内容追加到模式空间中,并使用一个新行作为分隔符
* `G`
使用一个单独的新行,追加保持空间中的内容到模式空间中
![The Sed get command][26]
将保持命令和获取命令一起使用,可以允许你去存储并调回数据。作为一个小挑战,我让你重写前一节中的示例,将输入文件的第 1 行放置在第 5 行之后,但是这次必须使用获取和保持命令(使用大写或小写命令的版本)而不能使用交换命令。带点小运气,可以更简单!
同时,我可以给你展示另一个示例,它能给你一些灵感。目标是将拥有登录 shell 权限的用户与其它用户分开:
![The Sed `get` command][26]
将 hold 命令和 get 命令一起使用,可以允许你去存储并调回数据。作为一个小挑战,我让你重写前一节中的示例,将输入文件的第 1 行放置在第 5 行之后,但是这次必须使用 get 和 hold 命令(注意大小写)而不能使用 exchange 命令。只要运气好,它将使那个方式更简单!
在这期间,我可以给你展示另一个示例,它能给你一些灵感。目标是将拥有登录 shell 权限的用户与其它用户分开:
```
cat -n inputfile | sed -En -e '
\=(/usr/sbin/nologin|/bin/false)$= { H;d; }
# 追回匹配的行到 hold 空间
# 然后继续下一个循环
p # 输出其它行
$ { g;p } # 在最后一行上
# 取得并输出 hold 空间中的内容
# 追回匹配的行到保持空间
# 然后继续下一个循环
p # 输出其它行
$ { g;p } # 在最后一行上
# 获取并打印保持空间中的内容
'
```
### 复习 print、delete 和 next
现在你已经更熟悉使用 hold 空间了,我们回到 print、delete 和 next 命令。我们已经讨论了小写的 `p`、`d` 和 `n` 命令了。而它们也有大写的版本。因为每个命令都有大小写版本,似乎是 Sed 的习惯,这些命令的大写版本将与多行缓冲区有关:
* `P`
将模式空间中第一个新行之前的内容输出
* `D`
删除模式空间中的内容并且包含新行,然后不读取任何新的输入而是使用剩余的文本去重启一个循环
* `N`
使用一个换行符作为新旧数据的分隔符,然后读取并追加一个输入的新行到模式空间。继续运行当前的循环。
### 复习打印、删除和次行命令
现在你已经更熟悉使用保持空间了,我们回到打印、删除和次行命令。我们已经讨论了小写的 `p`、`d` 和 `n` 命令了。而它们也有大写的版本。因为每个命令都有大小写版本,似乎是 Sed 的习惯,这些命令的大写版本将与多行缓冲区有关:
* `P` 将模式空间中第一个新行之前的内容输出
* `D` 删除模式空间中第一个新行之前的内容(包含新行),然后不读取任何新的输入而是使用剩余的文本去重启一个循环
* `N` 读取输入并追加一个新行到模式空间,用一个新行作为新旧数据的分隔符。继续运行当前的循环。
![The Sed uppercase `Delete` command][27]
![The Sed uppercase `Next` command][28]
这些命令的使用场景主要用于实现队列([FIFO 列表][29])。从一个输入文件中删除最后 5 行就是一个很权威的例子:
```
cat -n inputfile | sed -En -e '
1 { N;N;N;N } # 确保 pattern 空间中包含 5 行
1 { N;N;N;N } # 确保模式空间中包含 5 行
N # 追加第 6 行到队列中
P # 输出队列的第 1 行
D # 删除队列的第 1 行
N # 追加第 6 行到队列中
P # 输出队列的第 1 行
D # 删除队列的第 1 行
'
```
作为第二个示例,我们可以在两个列上显示输入数据:
```
# 输出两列
sed < inputfile -En -e '
$!N # 追加一个新行到 pattern 空间
# 除了输入文件的最后一行
# 当在输入文件的最后一行使用 N 命令时
# GNU Sed 和 POSIX Sed 的行为是有差异的
# 需要使用一个技巧去处理这种情况
# https://www.gnu.org/software/sed/manual/sed.html#N_005fcommand_005flast_005fline
$!N # 追加一个新行到模式空间
# 除了输入文件的最后一行
# 当在输入文件的最后一行使用 N 命令时
# GNU Sed 和 POSIX Sed 的行为是有差异的
# 需要使用一个技巧去处理这种情况
# https://www.gnu.org/software/sed/manual/sed.html#N_005fcommand_005flast_005fline
# 用空间填充第 1 行的第 1 个字段
# 并丢弃其余行
s/:.*\n/ \n/
s/:.*// # 除了第 2 行上的第 1 个字段外,丢弃其余的行
s/(.{20}).*\n/\1/ # 修剪并连接行
p # 输出结果
# 用空间填充第 1 行的第 1 个字段
# 并丢弃其余行
s/:.*\n/ \n/
s/:.*// # 除了第 2 行上的第 1 个字段外,丢弃其余的行
s/(.{20}).*\n/\1/ # 修剪并连接行
p # 输出结果
'
```
### 分支