【Linux】命令 - sed

Posted by 西维蜀黍 on 2019-08-02, Last Modified on 2023-08-27

Usage

usage: sed script [-Ealn] [-i extension] [file ...]
       sed [-Ealn] [-i extension] [-e script] ... [-f script_file] ... [file ...]
  • -i:直接修改文件内容

    # 将 pets.txt 文件中所有 abc 替换成 123 并写回原文件中
    $ sed -i "s/abc/123/g" pets.txt
    

开头 s - 替换匹配字符串

我使用下面的这段文本做演示:

$ cat pets.txt
This is my cat
  my cat's name is betty
This is my dog
  my dog's name is frank
This is my fish
  my fish's name is george
This is my goat
  my goat's name is adam

把其中的 my 字符串替换成 Wei’s,下面的语句应该很好理解

  • s 表示替换命令
  • /my/ 表示匹配my
  • /Wei’s/ 表示把匹配字符串替换成 Wei’s
  • /g 表示把一行中所有的匹配字符串都进行替换,如果没有 g 则只有每行第一个匹配的 my 被替换成 Wei’s
$ sed "s/my/Wei's/g" pets.txt
This is Wei's cat
  Wei's cat's name is betty
This is Wei's dog
  Wei's dog's name is frank
This is Wei's fish
  Wei's fish's name is george
This is Wei's goat
  Wei's goat's name is adam

注意:如果你要使用单引号,那么你没办法通过 \这样来转义。因此,用双引号就可以了,因为,在双引号内可以用 \” 来实现对双引号的转义。

只输出某行

sed -n '2p' < file.txt

will print 2nd line only

结尾 g - 在整行范围内替换

# 在整行范围内把test替换为mytest
$ sed 's/test/mytest/g' file1

如果没有g标记,则只有每行第一个匹配的test被替换成mytest。

-i - 重写回文件

再注意:上面的sed并没有对文件的内容改变,只是把处理过后的内容输出到标准输出,如果你要写回文件,你可以使用重定向,如:

$ sed "s/my/Wei's/g" pets.txt > hao_pets.txt

或使用 -i 参数直接修改文件内容:

# GNU下
$ sed -i "s/my/Wei's/g" pets.txt
# BSD下(macOS)
$ sed -i "" "s/my/Wei's/g" pets.txt

批量操作文件

批量操作当前目录下以 m 开头的文件:

$ sed -i 's/foo/bar/g' ./m*
$ sed -i 's/foo/bar/g' `grep foo -rl --include="m*" ./`

显示当前目录下所有的文件名

$ ls -lR <特定路径> |grep -v ^d|awk '{print $9}' |tr -s '\n'

在每一行最开头部分增加字符串

在每一行最开头部分增加字符串:

# 在每一行最开头部分增加字符串“#”, ^ 表示匹配每一行的最开头
$ sed 's/^/#/g' pets.txt
#This is my cat
#  my cat's name is betty
#This is my dog
#  my dog's name is frank
#This is my fish
#  my fish's name is george
#This is my goat
#  my goat's name is adam

在每一行最后面加点东西

在每一行最后面加点东西:

$ sed 's/$/ --- /g' pets.txt
This is my cat ---
  my cat's name is betty ---
This is my dog ---
  my dog's name is frank ---
This is my fish ---
  my fish's name is george ---
This is my goat ---
  my goat's name is adam ---

顺手介绍一下正则表达式的一些最基本的东西:

  • ^ 表示一行的开头。如:/^#/ 以#开头的匹配。
  • $ 表示一行的结尾。如:/}$/ 以}结尾的匹配。
  • \< 表示词首。 如:\<abc 表示以 abc 为首的词。
  • \> 表示词尾。 如:abc\> 表示以 abc 結尾的词。
  • . 表示任何单个字符。
  • * 表示某个字符出现了0次或多次。
  • [ ] 字符集合。 如:[abc] 表示匹配a或b或c(一次字符),还有 [a-zA-Z] 表示匹配任何大小或者小写的一个英文字符。如果其中有^表示反,如 [^a] 表示非a的字符

正规则表达式是一些很牛的事,比如我们要去掉某html中的tags:

<b>This</b> is what <span style="text-decoration: underline;">I</span> meant. Understand?

看看我们的sed命令

# 如果你这样搞的话,就会有问题
$ sed 's/<.*>//g' html.txt
 Understand?
 
# 要解决上面的那个问题,就得像下面这样。
$ sed 's/<[^>]*>//g' html.txt
This is what I meant. Understand?

指定指匹配第x行

只替换第3行的内容

$ sed "3s/my/your/g" pets.txt
This is my cat
  my cat's name is betty
This is your dog
  my dog's name is frank
This is my fish
  my fish's name is george
This is my goat
  my goat's name is adam

只替换第3到第6行的文本。

$ sed "3,6s/my/your/g" pets.txt
This is my cat
  my cat's name is betty
This is your dog
  your dog's name is frank
This is your fish
  your fish's name is george
This is my goat
  my goat's name is adam
$ cat my.txt
This is my cat, my cat's name is betty
This is my dog, my dog's name is frank
This is my fish, my fish's name is george
This is my goat, my goat's name is adam

只替换每一行的第一个s:

$ sed 's/s/S/1' my.txt
ThiS is my cat, my cat's name is betty
ThiS is my dog, my dog's name is frank
ThiS is my fish, my fish's name is george
ThiS is my goat, my goat's name is adam

只替换每一行的第二个s:

$ sed 's/s/S/2' my.txt
This iS my cat, my cat's name is betty
This iS my dog, my dog's name is frank
This iS my fish, my fish's name is george
This iS my goat, my goat's name is adam

只替换每一行的第3个以后的s:

$ sed 's/s/S/3g' my.txt
This is my cat, my cat'S name iS betty
This is my dog, my dog'S name iS frank
This is my fiSh, my fiSh'S name iS george
This is my goat, my goat'S name iS adam

macOS 中问题

error

# this works in Ubuntu
$ sed -i 's/hello/hola/' test.txt 
sed: 1: "test.txt": undefined label 'est.txt'

# how to fix
$ sed -i '' 's/hola/hey/' test.txt

What the man-page of sed tells us about sed -i:

Edit files in-place, saving backups with the specified extension. If a zero-length extension is given, no backup will be saved. It is not recommended to give a zero-length extension when in-place editing files, as you risk corruption or partial content in situations where disk space is exhausted, etc.

sed -i extension

Reference