# 修改文本

# tr

$ tr <源字符集> <目标字符集>   # 替换文本中的指定字符
     -c                      # 反选源字符集(即选中其它字符)
     -d                      # 删除源字符集
  • tr 命令的输入不能是文件,只能是 stdin ,且输出到 stdout 。
  • 例:
    cat f1 | tr a-z A-Z      # 将小写字母换成大写字母
    

# sed

$ sed [expression] [file]...  # 读取文件内容,根据表达式进行修改,然后输出
      -e                      # 读取 stdin
      -i                      # 将输出保存到源文件中,采用覆盖式写入(默认是输出到 stdout)
      -n                      # --quiet ,取消默认输出,此时使用 p 等命令才会有输出
  • 表达式示例:

    # 处理指定行
    -n '1p'                   # 只显示第 1 行
    -n '1,5p'                 # 只显示第 1~5 行
    '1,$d'                    # 删除第 1 行至最后一行(使用单引号作为定界符,避免将 $ 当做对变量取值),然后输出剩下的内容
    '1,4d;6d;$d'              # 删除第 1~4 行、第 6 行、最后一行(用 ; 分隔多个目标)
    '1i hello'                # 在第 1 行之前插入一行字符串
    '1a hello'                # 在第 1 行之后插入一行字符串
    'a  hello'                # 在每行之后插入一行字符串
    
    # 使用正则匹配
    -n '/hello/p'             # 找到正则匹配的每行并显示,相当于 grep 命令。如果不加 -n ,则会将原始文本也输出
    '/hello/d'                # 找到正则匹配的每行并删除
    
    # 使用正则替换
    's/源字符串/目标字符串/g'   # 替换字符串,源字符串采用基本正则语法
    's#^hello#hi#g'           # s 之后的第一个字符会被视作分隔符
    's#hello##g'              # 目标字符串为空,则会删除源字符串
    's#hello##2'              # 只替换第二次
    's#hello \(\w*\)#\1#g'    # 可以按 \1 的格式提取正则匹配的元素组
    
    '3 i Hello'               # 插入一行内容,作为第 3 行
    '0,/^hello/s##Hello#'     # 只执行一次正则替换
    
    • sed 正则表达式的特点:
      • 大部分元字符需要加上 \ 转义,除了 ^$.*[]
      • 支持 \w、\s 及相反字符集,不支持 \d 字符集。
  • 例:

    cat f1 | sed 's#hello##g' > f2  # 将修改结果保存到另一个文件
    sed -i 's#hello##g' f1          # 将修改结果保存到源文件中
    
    [root@CentOS ~]# echo 'Hello World' | sed 's#Hello#Hi#g'
    Hi World
    [root@CentOS ~]# echo 'Hello World' | sed 's#Hello \(\w*\)#\1#g'
    World
    
    sed -i 's#first_line#Hello\
    World\
    first_line#g' f1      # 插入多行
    

# vim

  • vi 是类 Unix 系统的内置文本编辑器,而 vim 是一个流行的类 vi 编辑器,功能更多。

  • 同类软件:

    • nano :一个比 vi 功能更简单的文本编辑器。
    • less :一个只读的文本阅读器。
      • 用 vim 打开一个文件时,会将整个文件的内容加载到内存中,并扫描每行内容,进行语法突出显示。因此打开文件时有一定耗时,占用内存比整个文件的体积还大一些。
      • 使用 less 时,只会将文件的部分内容加载到内存中,比如只加载第 100~200 行的内容,显示给用户看,因此占用的内存很少。
      • 因此 vim 只适合打开低于 100MB 的文件。阅读大型文件时,建议用 less 命令。修改大型文件时,建议用 sed 命令。
  • 执行以下命令即可启动 vim 编辑器:

    $ vim [path]
    
    • 如果不指定 path ,则会打开一个空的编辑器界面。
    • 如果指定的 path 是一个文件,则对它进行编辑。如果该文件不存在,则可以在保存时创建它。
    • 如果指定的 path 是一个目录,则可以管理该目录下的文件。
    • vim 的命令支持组合,可以连续输入多条命令,组合它们的功能。

# 缓存文件

  • 用 vim 打开一个文件时,会在其目录下创建一个缓存文件,用于缓存文件的最后修改状态,命名格式为 .{filename}.swp
    • 当用户修改文件并保存时,会用缓存文件替换原文件,导致文件的 inode 变化。
  • 用 vim 打开一个文件时,如果提示当前已存在缓存文件,则可能是因为:
    • 此时有其他用户正在用 vim 打开该文件。
    • 上次修改了文件,但没有保存文件就异常退出 vim 。此时建议执行以下命令:
      vim -r .{filename}.swp  # 恢复到文件的最后修改状态
      :wq                     # 保存文件
      rm -f .{filename}.swp   # 删除缓存文件
      

# 命令模式

启动 vim 时,默认进入命令模式(Command mode):

  • 此时不能编辑文本,只能输入键盘上的某些字符作为命令(区分大小写)。
  • 文本末尾显示的 ~ 表示空行,并不是实际存在的字符。
  • vim 的命令支持组合,可以连续输入多条命令,组合它们的功能。
    • 比如输入一个数字 n 之后再输入 dd ,会连续剪贴 n 行。
  • 关于切换模式的命令:
    • i/a :进入插入模式。
    • o :在光标下方插入一行并进入插入模式。
    • r :替换光标所在的那个字符。
    • R :进入替换模式。
    • 输入以 :/? 开头的字符串会进入底线命令模式。
    • 进入其它模式之后,按 Esc 即可退出到命令模式。
  • 关于移动光标的命令:
    • PageUpPageDown :向上或下翻页。
    • kjhl :将光标向上、下、左、右移动一格。
    • Space :将光标后移一格。
    • Enter :将光标下移一行。
    • gg :将光标移动到第一行。
    • G :将光标移动到最后一行。
    • 输入 /word(或 ?word)会向下(或向上)查找 word 字符串,然后输入 n(或 N)会切换到下一个(或上一个)匹配结果。
  • 关于撤销的命令:
    • u :撤销上一次操作。
    • Ctrl + r :重做被撤销的操作。
    • . :重做上一次操作(对 u 和 Ctrl + r 无效)。
  • 关于复制粘贴的命令:
    • yy :复制光标所在的当前行。
    • xX :删除光标之后或之前的一个字符。
    • dd :剪贴当前行。
    • pP :粘贴到下一行或上一行。
    • v :开始选中,此时光标移动过的区域都会被反白选中,然后输入 d 或 y 即可删除或复制。
    • Ctrl + v :开始矩形选中。

# 底线命令模式

底线命令模式(Last line mode):

  • 此时输入的字符会显示在下方的命令行中。

  • 常用命令:

    • :wq :保存并退出(输入 w 表示保存,输入 q 表示退出)
    • :wq! :强制保存再退出(输入!表示强制执行操作)
    • :wq [文件名] :保存为指定文件。
    • :s/源字符串/目标字符串/g :在当前行替换字符串。(目标字符串为空的话就是删除)
    • :%s/源字符串/目标字符串/g :在每一行替换字符串。
    • :set nu :显示行号。
    • /str :向下查找字符串。然后输入 n(或 N)会切换到下一个(或上一个)匹配结果。
    • ?str :向上查找字符串。
  • 可以在 /etc/vimrc~/.vimrc 文件永久保存 vim 的配置。常见的配置如下:

    set encoding=utf-8  " 设置编码格式
    set number          " 显示行号
    set nonumber        " 不显示行号
    set ignorecase      " 搜索时不区分大小写
    set paste           " 进入粘贴模式,使粘贴的文本内容会原样地输入 vim
    set nopaste         " 退出粘贴模式
    set tabstop=4       " 每个制表符 \t 显示的宽度
    set expandtab       " 按下 Tab 键时,输入空格而不是制表符
    
    • 用双引号 " 声明单行注释。

# iconv

iconv [file]        # 转换文本文件的编码格式(默认输出到 stdout)
      -f utf-8      # 源文件的编码格式
      -t gbk        # 要转换成的编码格式
      -c            # 忽略转换失败的字符
  • 例:批量转换文件的编码格式
    file_list=`find . -name "*.txt"`
    from_encoding='utf-8'
    to_encoding='gbk'
    for f in $file_list
    do
        iconv $f -f utf-8 &> /dev/null
        if [ $? ]; then
            echo "Convert the encoding of file $f to $to_encoding"
            iconv $f -f $from_encoding -t $to_encoding > .iconv.tmp
            mv .iconv.tmp $f
        else
            echo "The encoding of file $f is not $from_encoding , skip."
            continue
        fi
    done