我的目录包含以或.idat
结尾的文件对列表。_Grn
_Red
对于每一对,我想创建一个以第一个_
分隔符之前的子字符串命名的目录,并将文件移动到各自的目录中。
如果目录不存在,请在移动文件之前创建它们。
我的代码:
for file in *.idat;
do directory_name=${file%_*} \
mkdir directory_name \
if ${file%_*}==directory_name;
then
mv $file directory_name;
fi;
done
追溯:
-bash: syntax error near unexpected token `then'
文件名:
00f3408c-5ad1-4afb-9eac-3392aa92e42c_noid_Grn.idat
00f3408c-5ad1-4afb-9eac-3392aa92e42c_noid_Red.idat
0317b249-9256-47fe-9533-3ca91c07e3fd_noid_Grn.idat
0317b249-9256-47fe-9533-3ca91c07e3fd_noid_Red.idat
039f8688-b4cd-4931-a8f5-40bcb1fbd8f0_noid_Grn.idat
039f8688-b4cd-4931-a8f5-40bcb1fbd8f0_noid_Red.idat
预期的文件夹名称:
00f3408c-5ad1-4afb-9eac-3392aa92e42c
0317b249-9256-47fe-9533-3ca91c07e3fd
039f8688-b4cd-4931-a8f5-40bcb1fbd8f0
答案1
应该是这样的:
shopt -s nullglob extglob # dotglob
for file in [^_]*_@(Grn|Red).idat; do
dirname=${file%%_*}
mkdir -p -- "$dirname" &&
mv -- "$file" "$dirname"
done
dotglob
(如果您还想考虑隐藏的,请取消注释)。
\
该行的末尾是一个行延续。它用于打破长行以提高可读性。
do directory_name=${file%_*} \
mkdir directory_name \
if ${file%_*}==directory_name
是相同的
do directory_name=${file%_*} mkdir directory_name if ${file%_*}==directory_name
因此它会要求mkdir
创建名为directory_name
,的目录if
,00f3408c-5ad1-4afb-9eac-3392aa92e42c_noid==directory_name
并directory_name=00f3408c-5ad1-4afb-9eac-3392aa92e42c_noid
在其环境中传递。
然后 shell 会抱怨then
没有相应的if
.
要在 中进行模式匹配bash
,您可以使用case
构造函数或[[ text = pattern ]]
运算符,但这里不需要。
--
另请记住,列表上下文中的扩展必须在 bash 中引用,并且对于大多数命令,非选项参数必须与选项分开。
${var%pattern}
删除最短与 末尾的模式匹配的字符串$var
。您需要${var%%pattern}
删除最长的字符串才能删除第一个字符串中的所有字符串_
。您会注意到,我们使用[^_]*...
as glob 模式来确保文件不以 a 开头,_
这会导致空目录名。
Grn
如果您知道每个文件总是有一个文件,则可以通过执行以下操作将和 的Red
调用次数减少一半:mkdir
mv
shopt -s nullglob # dotglob
for file in [^_]*_Red.idat; do
dirname=${file%%_*}
mkdir -p -- "$dirname" &&
mv -- "$file" "${file%_*}_Grn.idat" "$dirname"
done