关于linux:Bash技巧可以批量在多个目录名前面加上数字的Shell脚本

5次阅读

共计 5229 个字符,预计需要花费 14 分钟才能阅读完成。

本篇文章介绍一个能够批量在多个目录名后面加上数字的 shell 脚本。

假如这个 shell 脚本的名称为 digitname.sh

在理论的开发工作中,个别会在罕用的重要目录后面增加数字。

例如,把目录命名为“1- 开发文档”、“2- 部门文档”这种模式。

这样命名有如下的益处:

  • 在文件管理器查看时,以数字结尾的目录个别会排在后面。

    当目录下多个子目录时,不须要滚动页面就能看到这些重要目录,不便查看。

  • 在目录名后面加上不同的数字,在文件管理器中,这些目录的程序会绝对固定。

    后续再新建目录,也不会打乱这些目录的程序。便于集体记忆。

  • 在 Linux 下应用 cd 命令进入罕用目录时,只须要输出后面的数字,就能用 Tab 键补全。

    能够防止切换输入法来输出中文。或者有一些目录名的后面几个字符雷同时,能够防止要输出多个字符后能力补全。

上面介绍的 digitname.sh 脚本就是用于在目录名、文件名后面加上数字和‘-’字符。

该脚本反对的性能阐明如下:

  • 应用 -p 选项,在所给文件名后面加上数字,且数字会从 1 开始递增。
  • 应用 -r 选项,去掉所给文件名后面的数字、以及数字前面的‘-’字符。

    提供这个性能次要是为了对指定的目录名从新排序。

    例如,原先 12 个目录的目录名后面别离增加了数字 1 到 12。

    前面删掉了数字 5、数字 9 结尾的目录。那么残余目录的数字程序就不连贯。

    如果想要从新连贯数字程序,就能够应用 -r 选项先去掉目录名后面的数字,再应用 -p 选项进行重命名。

  • 应用 -i 选项,把所给文件名后面的数字加 1。
  • 应用 -m 选项,基于所给的目录名创立新的目录,会在目录名后面主动加上数字和‘-’字符。

    数字值是当前目录下子目录名的最大数字加上 1。

脚本代码

列出 digitname.sh 脚本的具体代码如下所示。

在这个代码中,对大部分要害代码都提供了具体的正文,不便浏览。

这篇文章的前面也会提供一个参考的调用例子,有助了解。

#!/bin/bash
# 该脚本用于对所给文件名进行重命名、以及创立新的目录. 阐明如下:
# - 在所给文件名后面加上数字, 且数字会递增.
# - 去掉所给文件名后面的数字、以及数字前面的 '-' 字符.
# - 把所给文件名后面的数字加 1.
# - 基于所给的目录名创立新的目录, 会在目录名后面主动加上数字
#   和 '-' 字符. 数字值是当前目录下子目录名的最大数字加上 1.

show_help()
{
printf "USAGE
    $(basename $0) option [dirname1 ... [dirnamen]]
OPTIONS
    option: 必须提供的选项参数. 每次只能提供一个选项. 反对的选项如下:
        -h: 打印这个帮忙信息, 而后退出脚本.
        -p: 在所给的文件名后面加上数字, 且数字会递增. 例如, 所给的
            文件名是 a b c, 则把对应文件名别离重命名为 1-a 2-b 3-c.
        -r: 去掉所给文件名后面的数字、以及数字前面的 '-' 字符. 例如,
            所给的文件名是 1-a 22-b 333-c, 则会别离重命名为 a b c.
            如果所给文件名的结尾不合乎 '数字 -' 这个格局, 不做解决.
        -i: 把所给文件名后面的数字加 1, 并重命名该文件. 例如, 所给的
            文件名是 1-a 22-b 333-c, 则会别离重命名为 2-a 23-b 334-c.
            如果所给文件名的结尾不合乎 '数字 -' 这个格局, 不做解决.
        -m: 基于所给的目录名创立新的目录, 会在目录名后面主动加上数字
            和 '-' 字符. 数字值是当前目录下子目录名的最大数字加上 1.
    dirname1 ... dirnamen: 可选的文件名参数
        对于 -p/-r/-i 参数来说, 前面提供的参数就是要解决的文件名参数.
        如果没有文件名参数, 默认应用当前目录下的子目录名.

        对应 -m 参数来说, 前面提供的参数是要创立的目录名后缀局部.
        理论创立的目录名会在所给目录名参数后面加上数字和 '-' 字符.
        < 留神 >: 提供 -m 选项时, 前面必须提供的目录名参数.
NOTE
    -p 是 prefix 的简写. -r 是 remove 的简写. -i 是 increase 的简写.
    -m 是 mdkir 的简写. 能够依照这些单词含意来帮忙记忆每个选项的作用.
"
}

# 该函数重命名所给的每一个文件名, 会在文件名后面增加数字. 数字从 1 开始
# 递增. 例如, 所给的文件名参数是 a b c, 则会别离重命名为 1-a 2-b 3-c.
prefix_digit_to_filename()
{if [ $# -eq 0]; then
        echo "Usage: $FUNCNAME filename1 [filename2 ...[filenamen]]"
        return 1
    fi
    # 在文件名后面增加的数字从 1 开始. 如有须要, 能够改成从 0 开始.
    local number=1

    local filename
    for filename in "$@"; do
        # 不判断文件名是否曾经以数字结尾. 间接在文件名后面增加数字.
        mv -v "${filename}" "$((number++))-${filename}"
    done
}

# 该函数重命名所给的每一个文件名, 会去掉文件名后面的数字和 '-' 字符.
# 例如, 所给的文件名参数是 1-a 22-b 333-c, 则会别离重命名为 a b c.
remove_filename_prefix_digit()
{if [ $# -eq 0]; then
        echo "Usage: $FUNCNAME filename1 [filename2 ...[filenamen]]"
        return 1
    fi

    # 在 Linux 中, mv 命令重命名每次只能解决一个文件名. 而 rename 命令
    # 能够解决多个文件, 且能够应用正则表达式来示意要替换的文件名内容.
    # rename 命令应用 perl 正则表达式. 能够应用 \d 匹配任意一个数字.
    # 用 + 匹配一次或屡次前一个字符. 则 ^\d+ 匹配文件名结尾的所有数字.
    # 在 ^\d+ 前面的 - 对应 '-' 字符本身. 要求在数字前面跟着 '-' 字符.
    # 上面的命令把文件名结尾的数字和 '-' 字符替换为空, 从而去掉数字.
    rename -v 's/^\d+-//' "$@"
}

# 该函数重命名所给的每一个文件名, 会把所给文件名结尾的数字加 1. 例如,
# 所给的文件名参数是 1-a 22-b 333-c, 则会别离重命名为 2-a 23-b 334-c.
increase_filename_number()
{if [ $# -eq 0]; then
        echo "Usage: $FUNCNAME filename1 [filename2 ...[filenamen]]"
        return 1
    fi

    # 在 perl 的 s///e 表达式中, 增加最初面的 e 指定评估表达式. 如果
    # 不加最初面的 e, 只会进行字符串拼接, 而不是进行算术运算. 应用
    # 小括号把 \d+ 括起来, 以便前面通过 $1 反向援用到 \d+ 匹配的内容.
    rename -v 's/^(\d+)-/sprintf("%d-",$1+1)/e' "$@"
}

# 基于所给的目录名创立新的目录. 目录名后面会加上数字, 数字前面跟着
# '-' 字符. 具体的数字值会从以后子目录名结尾最大的数字往上递增.
# 例如, 当前目录下, 结尾数字最大的子目录名是 333-c. 调用该函数时,
# 传入的目录名参数是 d, 则会创立一个新的 334-d 目录.
mkdir_digit_filename()
{if [ $# -eq 0]; then
        echo "出错: 应用 -m 选项时, 前面必须提供要创立的目录名."
        return 1
    fi

    # 关上 bash 的 extglob shell 选项, 能力在路径名扩大中应用
    # +(pattern-list) 来示意匹配一次或屡次所给模式. 这个选项的状态跟
    # 所在的 shell 无关. 在以后 shell 关上该选项, 不影响父 shell 的状态.
    # 能够应用 shopt -p extglob 来查看该选项的状态. 默认应该是开的.
    # 这里被动关上该选项, 能够晋升移植性, 防止有些 Linux 版本没有关上.
    shopt -s extglob
    # 在关上 extglob 选项后, +([0-9])-*/ 会扩大为当前目录下, 以
    # 数字结尾、且前面跟着 '-' 字符的子目录名, 不蕴含文本文件名.
    # 应用 ls -d 命令逐行打印扩大失去的子目录名, 并传递给 awk 解决.
    # awk 以 '-' 宰割所给字符串, 获取子目录名后面的数字, 输入最大的数字.
    local maxnumber=`ls -d +([0-9])-*/ | \
        awk -F '-' '{if (x < $1) x = $1 } END {print x}'`

    local dirname
    # 在所给的每一个目录名后面都加上数字, 并创立新的目录.
    # 目录名后面的数字会从以后子目录名结尾最大的数字往上递增.
    for dirname in "$@"; do
        mkdir -v "$((++maxnumber))-${dirname}"
    done
}

# 如果所给的第一个选项参数是 -h, 则打印帮忙信息, 而后就退出. 当没有
# 提供参数时, 也是打印帮忙信息, 而后退出. 要求至多要提供一个参数.
if ["$1" == "-h" -o $# -eq 0]; then
    show_help
    exit 0
fi

# 先保留第一个选项参数的值, 防止前面执行 shift 1 后, 获取不到这个值.
option_type="$1"
# 在进行后续操作时, 必须提供且只提供一个除了 -h 之外的选项参数.
# 上面用 shift 1 移除第一个选项参数, 剩下的就全是文件名参数.
shift 1

# 当所给的参数个数等于 0 时, 示意只提供了选项参数, 没有提供文件名参数.
# 则默认应用 */ 通配符来匹配当前目录下的子目录名. 在 bash 的路径名
# 扩大中, */ 这个写法的通配符示意只扩大为子目录名. 目前默认只解决
# 子目录名. 如果想要解决当前目录下的所有文件名, 能够把 */ 改成 *.
if [$# -eq 0]; then
    dirnames="*/"
else
    dirnames="$@"
fi

# 为了能够应用 */ 通配符进行扩大, 不要用双引号把 ${dir_list} 括起来.
if ["$option_type" == "-p"]; then
    prefix_digit_to_filename ${dirnames}
elif ["$option_type" == "-r"]; then
    remove_filename_prefix_digit ${dirnames}
elif ["$option_type" == "-i"]; then
    increase_filename_number ${dirnames}
elif ["$option_type" == "-m"]; then
    # 当创立新的目录时, 目录名由用户提供, 应用 $@ 获取所给的目录名参数.
    mkdir_digit_filename "$@"
else
    echo "出错: 所给的第一个选项参数不反对, 请应用 -h 选项查看帮忙信息."
    exit 2
fi

exit

一个参考的测试例子

digitname.sh 脚本文件放到 bash shell 的当前工作目录下,增加可执行权限。

具体测试如下:

$ mkdir testrename
$ cd testrename
[testrename]$ mkdir 1-a 22-b 333-c
[testrename]$ ls
1-a  22-b  333-c
[testrename]$ ./digitname.sh -r
1-a/ renamed as a/
22-b/ renamed as b/
333-c/ renamed as c/
[testrename]$ ls
a  b  c
[testrename]$ ./digitname.sh -p a b‘a’->‘1-a’‘b’->‘2-b’[testrename]$ ls
1-a  2-b  c
[testrename]$ ./digitname.sh -i 2-b/
2-b/ renamed as 3-b/
[testrename]$ ls
1-a  3-b  c
[testrename]$ ./digitname.sh -m c
mkdir: created directory‘4-c’[testrename]$ ls
1-a  3-b  4-c  c

下面命令先在当前工作目录下创立一个 testrename 目录。

而后进入该目录,又创立了 1-a、22-b、333-c 三个子目录。

执行 ./digitname.sh -r 命令时,没有提供文件名参数,默认会解决当前目录下的所有子目录。

这里把 1-a、22-b、333-c 三个子目录别离重命名为 a、b、c

即,去掉了目录名后面的数字和‘-’字符。

执行 ./digitname.sh -p a b 命令,提供的文件名参数是 a b

这会把 a、b 这两个目录别离重命名为 1-a、2-b

即,在目录名后面增加上数字和‘-’字符。数字从 1 开始递增。

执行 ./digitname.sh -i 2-b/ 命令,把所给的 2-b 目录后面的数字加 1,重命名为 3-b

执行 ./digitname.sh -m c 命令,会把当前目录下子目录名最大的数字加 1 后的值,增加到所给的目录名参数后面。

当前目录下子目录名最大的数字是 3,加 1 之后是 4,创立了 4-c 目录。

留神:尽管当前目录下有一个名为 c 的目录,然而 ./digitname.sh -m c 命令并不会重命名这个 c 目录。

而是用增加了数字后的目录名来创立一个新的目录。

测试完结后,能够执行上面命令来删除所创立的测试目录和文件:

rm -r testrename/
正文完
 0