如何在 bash 中干净地循环遍历子目录并恢复它们的名称?

如何在 bash 中干净地循环遍历子目录并恢复它们的名称?

我的项目分为三个目录:数据、脚本和结果。主管道从这三个目录之上的目录调用。数据包含一系列子目录,我想循环这些子目录,恢复它们的名称,并且为了保留顺序,在结果中创建具有相同名称的新目录。我使用以下脚本执行此操作:

for d in data/*
   do 
   newname=$(echo $d | cut -f2 -d /)
   mkdir /results/$newname
   myprogram $d/raw_data > ../results/$newname/output
   done

它可以完成这项工作,但我发现必须删减目录名称并创建附加变量很麻烦。有没有更优雅的方法来做到这一点?我可以一步检索子目录的名称,这样我就可以执行以下操作:

for d in (??????)
   do
   mkdir /Results/$d
   myprogram Data/$d/rawdata > results/$d/output
   done

编辑 我刚刚想到了第一行这个想法,它与第二段代码配合得很好

for d in $(ls -d  data/* | cut -f2 -d /)

有人有更好的建议吗?

答案1

可以通过删除前缀来处理:

for d in data/*
do
   mkdir "./results/${d#*/}"
   myprogram "$d/raw_data" > "../results/${d#*/}/output"
done

该构造${d#*/}被称为前缀删除/。它会删除字符串中第一个字符之前的所有内容$d。例如:

$ d=data/subdir1
$ echo "${d#*/}"
subdir1

笔记

  1. 除非您想要进行单词拆分和路径名扩展,否则所有 shell 变量都应放在双引号中。

  2. ls旨在产生人性化的输出。例如,显示的文件名旨在显示得很漂亮,并不一定与实际文件名匹配。应避免在脚本中ls使用。ls

  3. 替代方案前缀删除如上所示是可执行文件dirname

文档

man bash

${参数#单词}
${参数##单词}

删除匹配的前缀模式。单词被扩展以产生一个模式,就像在路径名扩展中一样。如果模式与参数值的开头匹配,则扩展的结果为参数的扩展值,其中删除了最短的匹配模式(case #)或最长的匹配模式(##case)。如果参数是@或*,则模式删除操作将依次应用于每个位置参数,扩展为结果列表。如果参数是一个以@或*为下标的数组变量,则模式删除操作将依次应用于数组的每个成员,扩展为结果列表。

相关内容