c# 找出目录下的所有子目录_Bash技巧:可以批量在多个目录名前面加上数字的Shell脚本

本篇文章介绍一个可以批量在多个目录名前面加上数字的 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 0fi# 先保存第一个选项参数的值,避免后面执行 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 2fiexit

一个参考的测试例子

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

具体测试如下:

$ mkdir testrename$ cd testrename[testrename]$ mkdir 1-a 22-b 333-c[testrename]$ ls1-a  22-b  333-c[testrename]$ ./digitname.sh -r1-a/ renamed as a/22-b/ renamed as b/333-c/ renamed as c/[testrename]$ lsa  b  c[testrename]$ ./digitname.sh -p a b‘a’ -> ‘1-a’‘b’ -> ‘2-b’[testrename]$ ls1-a  2-b  c[testrename]$ ./digitname.sh -i 2-b/2-b/ renamed as 3-b/[testrename]$ ls1-a  3-b  c[testrename]$ ./digitname.sh -m cmkdir: created directory ‘4-c’[testrename]$ ls1-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/
bd05c93607f459f2fc83329f59550dd0.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值