批量 文本内容替换, 改文件名 shell 脚本

晨曦之光 发布于 2012/05/23 11:02
阅读 4K+
收藏 0

原文:批量文本内容替换, 改文件名 shell 脚本
作者:Breaker <breaker.zy_AT_gmail>


写了个 shell 脚本 repren.sh,替换当前目录下的文本文件(根据扩展名、文件名决定)中的字符串 OLD_TEXT 为 NEW_TEXT,将含 OLD_TEXT 的文件名重命名为 NEW_TEXT

用途例子:改变 VC 工程中的工程名
改进说明:可将 FIND_REGEX(文件扩展名)、SED_REGEX(文本边界)、GREP_REGEX(文件名边界)的选择作为脚本命令选项, 或从另一文件中读取配置
限制说明:只是个文本替换小模型,没测中文

功能

假设如此调用脚本 repren.sh:

repren.sh Tom Jerry
OLD_TEXT=Tom
NEW_TEXT=Jerry

按顺序做以下一些事:

1. 查找目录及子目录中的以下文件(大小写无关):

  • 文件名是:makefile、readme

  • 扩展名是:

    .h、.hxx、.hpp、.c、.cpp、.cxx
    .txt
    .mak、.rc
    .xml、.html、.xhtml
    .sln、.vcproj

查找的文件名正则表达式规则在 FIND_REGEX 中定义

2. 将找到的文件中的文本 Tom 替换为 Jerry:

Tom => Jerry: 严格大小写替换
TOM => JERRY: 全大写替换
tom => jerry: 全小写替换

但不替换:
tOm => Jerry: 混合大小写替换

Tom 两边可以有新行、空格、TAB、数字 0-9,以及这些 ASCII 标准标点符号

. , : ; _ - = + * ~ ! @ # $ % ^ & ' " < > [ ] ( ) { } / \ ? ` |

此时都可成功替换

但不能替换:
aaTombb => aaJerrybb
此时可修改 SED_REGEX='\(\b\|[0-9a-zA-Z_]\)',上面替换即可成功进行,但也会做下面替换:
Tomorrow => Jerryorrow

2. 对上面的文件,如果文件名中含 Tom,将其重命名为 Jerry

重命名支持混合大小写替换,即:
tOm_test.cpp => Jerry_test.cpp

重命名时,Tom 两边可以有的字符和 1 相同
不能替换:
TomTest.cpp => JerryTest.cpp
此时可修改 GREP_REGEX='(\b|[0-9a-zA-Z_]),但也会做下面替换:
Tomorrow.cpp => Jerryorrow.cpp

3. 对于当前目录下的所有子目录的目录名,做和 2 相同的事

shell 脚本代码

#!/bin/bash

################################################################################
# Name: repren.sh
# Description:
#   按顺序做以下事情:
#   1. 查找特定类型的文件,如 .h、.cpp
#   2. 将文件内容中的文本 OLD_TEXT 替换成 NEW_TEXT
#   3. 将含 OLD_TEXT 的文件名重命名为 NEW_TEXT
#   4. 将含 OLD_TEXT 的目录名重命名为 NEW_TEXT
#
# Author:   Breaker <breaker.zy_AT_gmail>
# Date:     2011-10
################################################################################

# IFS 表示 for 语句中各项之间的分隔符
OLDIFS = $IFS
IFS = $'\n'   # $ 使字面量启动转义,否则 \n 为直接字面量而非 LF
SCRIPT_NAME = `basename "$0" `

# 用法
usage()
{
    echo "usage:"
    echo "  $SCRIPT_NAME OLD_TEXT NEW_TEXT"
}

if [ $# -lt 2 ]; then
    usage
    exit -1
fi

# 替换前后的 文本
OLD_TEXT = "$1"
NEW_TEXT = "$2"

OLD_TEXT_UPPER = ` echo $OLD_TEXT | tr '[a-z]' '[A-Z]' `     # 全大写的 旧文本
OLD_TEXT_LOWER = ` echo $OLD_TEXT | tr '[A-Z]' '[a-z]' `     # 全小写的 旧文本

NEW_TEXT_UPPER = ` echo $NEW_TEXT | tr '[a-z]' '[A-Z]' `     # 全大写的 新文本
NEW_TEXT_LOWER = ` echo $NEW_TEXT | tr '[A-Z]' '[a-z]' `     # 全小写的 新文本

echo -e 'replace text & rename file ...\n'

# 查找指定文件
FIND_REGEX = '.*(/(makefile|readme)|\.(h|hxx|hpp|c|cpp|cxx|txt|mak|rc|x(ht)?ml|html?|sln|vcproj))'
FILES = `find -type f -regextype posix-egrep -iregex "$FIND_REGEX" `

# 文本替换时的 字符串边界
#SED_REGEX='\(\b\|_\)'
SED_REGEX = '\(\b\|[0-9_]\)'
#SED_REGEX='\(\b\|[0-9a-zA-Z_]\)'

# 重命名时的 文件名边界
#GREP_REGEX='(\b|_)'
GREP_REGEX = '(\b|[0-9_])'
#GREP_REGEX='(\b|[0-9a-zA-Z_])'

# 对每个查找到的文件去做...
for EACH in $FILES
do
    # 替换文件中的文本 OLD_TEXT 为 NEW_TEXT
    sed -i "s/$SED_REGEX$OLD_TEXT$SED_REGEX/\1$NEW_TEXT\2/g" $EACH
    sed -i "s/$SED_REGEX$OLD_TEXT_UPPER$SED_REGEX/\1$NEW_TEXT_UPPER\2/g" $EACH
    sed -i "s/$SED_REGEX$OLD_TEXT_LOWER$SED_REGEX/\1$NEW_TEXT_LOWER\2/g" $EACH
    echo "$EACH: replace: $OLD_TEXT => $NEW_TEXT"

    # 重命名含 OLD_TEXT 的文件名为 NEW_TEXT
    OLD_FILE_0 = `basename $EACH | grep -E -i "$GREP_REGEX$OLD_TEXT$GREP_REGEX" `    # 只针对文件名,不管目录部分
    if [ "$OLD_FILE_0" ! = "" ]; then
        DIR = `dirname $EACH `
        OLD_FILE = "$DIR/$OLD_FILE_0"

        NEW_FILE_0 = ` echo "$OLD_FILE_0" | sed "s/$OLD_TEXT/$NEW_TEXT/gi" `
        NEW_FILE = "$DIR/$NEW_FILE_0"

        mv "$OLD_FILE" "$NEW_FILE"
        echo "rename: $OLD_FILE => $NEW_FILE"
    fi

    echo ''
done

echo -e 'rename dir ...\n'

# 更改目录名:重命名含 OLD_TEXT 的目录名
DIRS = `find -type d `
for EACH in $DIRS; do
    OLD_DIR_0 = `basename $EACH | grep -E -i "$GREP_REGEX$OLD_TEXT$GREP_REGEX" `
    if [ "$OLD_DIR_0" ! = "" ]; then
        OLD_DIR_DIR = `dirname $EACH `
        OLD_OLD_DIR = "$OLD_DIR_DIR/$OLD_DIR_0"

        NEW_DIR_0 = ` echo "$OLD_DIR_0" | sed "s/$OLD_TEXT/$NEW_TEXT/gi" `
        NEW_DIR_DIR = ` echo "$OLD_DIR_DIR" | sed "s/$OLD_TEXT/$NEW_TEXT/gi" `

        # find 先输出父目录,所以父目录这时已经重命名了
        # 所以 OLD_DIR 由新的父目录名和 OLD_DIR_0 拼成,而不是原来的 OLD_OLD_DIR 了
        OLD_DIR = "$NEW_DIR_DIR/$OLD_DIR_0"
        NEW_DIR = "$NEW_DIR_DIR/$NEW_DIR_0"

        mv "$OLD_DIR" "$NEW_DIR"
        echo "rename: $OLD_OLD_DIR => $NEW_DIR"
        echo ''
    fi
done

# 恢复环境
IFS = $OLDIFS

相关工具

25 Text Batch Processing Tools Reviewed: 25 种文本批量处理工具评估,文本查找、替换、正则表达式支持


原文链接:http://blog.csdn.net/breakerzy/article/details/6879244
加载中
返回顶部
顶部