我的项目分为三个目录:数据、脚本和结果。主管道从这三个目录之上的目录调用。数据包含一系列子目录,我想循环这些子目录,恢复它们的名称,并且为了保留顺序,在结果中创建具有相同名称的新目录。我使用以下脚本执行此操作:
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
笔记
除非您想要进行单词拆分和路径名扩展,否则所有 shell 变量都应放在双引号中。
ls
旨在产生人性化的输出。例如,显示的文件名旨在显示得很漂亮,并不一定与实际文件名匹配。应避免在脚本中ls
使用。ls
替代方案前缀删除如上所示是可执行文件
dirname
。
文档
从man bash
:
${参数#单词}
${参数##单词}删除匹配的前缀模式。单词被扩展以产生一个模式,就像在路径名扩展中一样。如果模式与参数值的开头匹配,则扩展的结果为参数的扩展值,其中删除了最短的匹配模式(case
#
)或最长的匹配模式(##
case)。如果参数是@或*,则模式删除操作将依次应用于每个位置参数,扩展为结果列表。如果参数是一个以@或*为下标的数组变量,则模式删除操作将依次应用于数组的每个成员,扩展为结果列表。