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

时间:2017-07-25 16:46:55

标签: regex bash for-loop if-statement file-rename

我需要一些关于重命名目录的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...

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

感谢您帮助我...

2 个答案:

答案 0 :(得分:1)

这可以使用与捕获组匹配的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):捕获&#34;控制&#34;或&#34; timesport&#34;进入第二个捕获组。
  • _[[:digit:]]+:匹配所有其他内容。
  • $:匹配字符串结尾。

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

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

答案 1 :(得分:1)

解决问题的另一种方法是将-_添加到IFS并将每个目录分成四个组件,将subj-添加到开头并使用$(())来解析/从第二个组件中删除前导零,然后使用第三个未更改的,例如(例如,我只是从文件中读取您的dirnames,但您可以使用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