bash中如何将多个目录重命名为相应的文件名

How to rename multiple directories into corresponding file names in bash

我需要一些有关重命名目录的 bash 脚本的帮助:

我想先重命名六个目录,以便进行分析:

这是重命名的原始目录名称:

MCIA-1-control_20170509
MCIA-2-control_20170509
MCIA-03-timesport_20170717
MCIA-04-timesport_20170717
MCIA-05-timesport_20170717
MCIA-6-timesport_20170717

我需要重命名如下:

subj-1-control
subj-2-control
subj-3-timesport
subj-4-timesport
subj-5-timesport
subj-6-timesport

我已经声明了几个变量如下:

$fnIDs #e.g.MCIA-1-control_20170509... 
$ren #e.g. 1-control...
$raw_dir #data directory

然后我运行这个循环,但是结果并没有像我预期的那样:

for fn in ${fnIDs}; do 
    echo "+++this is all folder name for rename: fnIDs:${fnIDs}+++"
    echo "+++renameing folder: fn:${fn}+++"

    for rn in ${ren}; do
        echo "=======ADD "subj" to rename the subj folder==========="
        refn=subj-"$rn" #e.g. subj-1-control...
        echo "refn:$refn"
        echo "rename folder $fn to $refn"

        if ( test -d "$raw_dir"/"$fn"); then #if dir exist then
            cp -R "$raw_dir"/"$fn" "$raw_dir"/"$refn" #copy and rename file
            echo "cp rename the subj folder:$raw_dir/$refn"
        elif ( test -d "$raw_dir"/"$refn");then
            echo "++++++renamed subject folder already exists+++++++"           
        else
            echo "+++++somthing went wrong!Name of subject folder does not exists check "$fn $refn"+++++++++"
            exit
        fi
    done
done

当我执行上面的脚本时,他们做的事情如下:

+++renameing folder: fn:MCIA-1-control_20170509+++
=======rename the subj folder===========
renfn:subj-1-control
rename folder MCIA-1-control_20170509 to subj-1-control
rename folder MCIA-1-control_20170509 to subj-2-control

我想做的是:

rename folder MCIA-1-control_20170509 to subj-1-control
rename folder MCIA-2-control_20170509 to subj-2-control...

基本上,它将原始文件夹名称重命名为六个不同的子文件夹名称... 我在这里卡住了一段时间...

谢谢你帮我...

这可以使用 bash 与捕获组匹配的正则表达式来完成。

代码

read -r -d '' input <<END
MCIA-0-control_20170509
MCIA-1-control_20170509
MCIA-2-control_20170509
MCIA-03-timesport_20170717
MCIA-04-timesport_20170717
MCIA-05-timesport_20170717
MCIA-6-timesport_20170717
END

for name in $input; do
    [[ $name =~ ^MCIA-0*([[:digit:]]+)-(control|timesport)_[[:digit:]]+$ ]] &&
            echo mv "$name" "subj-${BASH_REMATCH[1]}-${BASH_REMATCH[2]}"
done

输出

mv MCIA-0-control_20170509 subj-0-control
mv MCIA-1-control_20170509 subj-1-control
mv MCIA-2-control_20170509 subj-2-control
mv MCIA-03-timesport_20170717 subj-3-timesport
mv MCIA-04-timesport_20170717 subj-4-timesport
mv MCIA-05-timesport_20170717 subj-5-timesport
mv MCIA-6-timesport_20170717 subj-6-timesport

说明

  • ^: 匹配字符串的开头。
  • MCIA-:匹配当前目录前缀。
  • 0*:可选择匹配任意数量的前导零。这些不进入捕获组,因为我们要丢弃它们。
  • ([[:digit:]]+):丢弃前导零后,将一个或多个剩余数字捕获到第一个捕获组中。
  • -:匹配并丢弃额外的连字符。
  • (control|timesport):将"control"或"timesport"捕获到第二个捕获组中。
  • _[[:digit:]]+: 匹配其余所有。
  • $: 匹配字符串结尾。

如果输入字符串匹配,则构建 mv 命令,目标为 "subj"、第一个捕获组和第二个捕获组的串联。出于测试目的,我的代码示例使用 echo 而不是 运行 来打印命令。您可以根据需要通过验证、存在性检查等进行扩展,就像您在原始代码示例中所做的那样。

有关 bash 中正则表达式的更多详细信息,请参阅 Advanced Bash-Scripting Guide - 18.1. A Brief Introduction to Regular Expression

解决该问题的另一种方法是将 -_ 添加到 IFS 并将每个目录名分成四个部分,将 subj- 添加到开头并使用 $(()) resolve/remove 来自第二个组件的前导零,然后使用第三个不变的,例如(出于示例目的,我只是从文件中读取您的目录名,但您可以使用 globbing 或 find 将它们提供给 while 循环),例如

$ cat dirs.txt
MCIA-1-control_20170509
MCIA-2-control_20170509
MCIA-03-timesport_20170717
MCIA-04-timesport_20170717
MCIA-05-timesport_20170717
MCIA-6-timesport_20170717

那就简单了:

$ oifs="$IFS"; IFS="$IFS-_";   ## save old IFS, set new IFS
  while read -r dir; do        ## read each dirname
      arr=( $dir )             ## separate into array elements
      echo "mv $dir subj-$((${arr[1]}))-${arr[2]}"  ## use elements 1, 2
done < dirs.txt
IFS="$oifs"                    ## restore original IFS
mv MCIA-1-control_20170509 subj-1-control
mv MCIA-2-control_20170509 subj-2-control
mv MCIA-03-timesport_20170717 subj-3-timesport
mv MCIA-04-timesport_20170717 subj-4-timesport
mv MCIA-05-timesport_20170717 subj-5-timesport
mv MCIA-6-timesport_20170717 subj-6-timesport

要避免使用数组,您可以执行类似以下操作:

$ while read -r dir; do 
    echo $dir | 
    { IFS="$IFS-_"; read -r a b c d; echo "mv $dir subj-$((b))-$c"; }
done < dirs.txt
mv MCIA-1-control_20170509 subj-1-control
mv MCIA-2-control_20170509 subj-2-control
mv MCIA-03-timesport_20170717 subj-3-timesport
mv MCIA-04-timesport_20170717 subj-4-timesport
mv MCIA-05-timesport_20170717 subj-5-timesport
mv MCIA-6-timesport_20170717 subj-6-timesport