.. _sed:
============
sed
============
``.`` 是metacharacter,需要转义
==================================
在 ``sed`` 替换 ``.`` (点)时候,需要在 ``.`` 点符号前面加上::
\
做转义
.. literalinclude:: ../../devops/docs/pandoc/m2r
:language: bash
:caption: 通过SSH将本地Markdown文件上传服务器使用pandoc转换reStructuredText文件下载
:emphasize-lines: 3,4
删除字符串的最后n个字符
==========================
:ref:`bash` 提供了 :ref:`remove_last_n_characters_from_a_string_in_bash`
使用sed也可以类似实现,例如删除最后一个字符::
var2=`echo $var2 | sed 's/.$//'`
删除最后2个字符::
var2=`echo $var2 | sed 's/..$//'`
删除文件的最后一个字符
=========================
注意,是删除文件的最后一个字符,而不是每一行的最后一个字符。这里有一个小技巧::
sed '$ s/.$//' sample.txt
请注意,这里 ``$`` 代表最后一行,所以才能实现只删除最后一行的最后一个字符,也就是文件的最后一个字符。
不要和::
sed 's/.$//' sample.txt
混淆,这是删除每一行的最后一个字符
将分隔符替换为换行
====================
``sed`` 可以直接使用 ``\n`` 作为换行符号的字符替换,例如,需要将文档中的 ``,`` 替换为换行符::
sed 's/,/\n/g' sample.txt
变量的困扰
===========
我最近遇到一个头疼的问题,就是我要将文件中的开头和结尾替换成一长串的 ``文件系统目录`` (作为 :ref:`rsync` 参数),我开始以为很简单,就是::
sed "s/^/${dir_string}/g" file
但是,实际上始终报错,系统参数 ``s`` 错误。我觉得很奇怪,做了很多尝试才发现,当 ``${dir_string}`` 变量被bash展开以后填入到 ``sed`` 中,会导致 ``sed`` 将路径中的 ``/`` 误判为字符串匹配指令之间的分隔符。这个问题我暂时没有找到解决方法,目前采用单是一个变通方法: 反过来做
先创建一个模版文件 ``sync_template`` 将同步命令写好,然后将最后一级子目录作为模版中需要替换的全大写字符长:
.. literalinclude:: sed/sync_template
:language: bash
:caption: 将替换字符串简化,避免 ``/`` 符号出现在替换字符串变量中
这样就能避免替换字符长复杂化,就直接执行::
dir="01GQZ0NMD4790X3ZAEG6PKVXE7"
cat sync_template | sed "s/DATA/${dir}/g"
FreeBSD平台的sed
======================
在BSD系统(包括 :ref:`macos` ), ``sed`` 的参数 ``-i`` 需要一个后缀,不能和linux平台一样 ``-i`` 参数是可选的。所以不能直接使用 ``-i`` 参数表示直接修改文件,而是要先给予一个 ``''`` 空白。另外,搜索和替换使用的是 ``@`` 符号,所以以下是一个案例:
.. literalinclude:: sed/bsd_sed
:caption: BSD平台的sed案例
这样就能够把 ``line`` 单词替换成 ``new`` 单词
参考
========
- `Sed Command in Linux/Unix with examples `_
- `Linux sed Command: How To Use the Stream Editor `_
- `sed, a stream editor `_ gnu sed官方手册,最全面的参考
- `Removing the Last Character of a File `_
- `sed -i on FreeBSD [duplicate] `_