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