带文件名的 For 循环

带文件名的 For 循环

我有几个文件(表),命名为:研究所_模型_设想_.txt

研究所模型设想, 和是变量。)我想创建一个for循环来识别具有相同研究所名称,同时相同设想名称,以便附加每个不同的结果模型在同一个输出文件中,使用以下命令:

paste filename1.txt filename2.txt > output_file.txt

我知道如何创建for不同文件夹的循环,但不知道如何创建文件名的循环。有人有想法吗?

作为一个最小的例子,文件名可以如下:

wbm_gfdl_rcp8p5_mississippi.txt
wbm_hadgem_rcp8p5_mississippi.txt
matsiro_gfdl_rcp8p5_mississippi.txt
matsiro_ipsl_rcp4p5_mississippi.txt
matsiro_hadgem_rcp4p5_mississippi.txt
matsiro_miroc_rcp8p5_mississippi.txt

然后,我想将以下文件附加在一起:

wbm_gfdl_rcp8p5_mississippi.txt with
wbm_hadgem_rcp8p5_mississippi.txt

matsiro_ipsl_rcp4p5_mississippi.txt with
matsiro_hadgem_rcp4p5_mississippi.txt

matsiro_gfdl_rcp8p5_mississippi.txt with
matsiro_miroc_rcp8p5_mississippi.txt

答案1

首先,for目录循环和文件循环没有区别。它们完全一样。请记住,在 *nix 上,一切皆文件

因此,你的循环将是这样的:

for institute in institute1 institute2 institute3
do
    for scenario in scenario1 scenario2 scenario3
    do
        paste "$institute"_*_"$scenario"* > "$institute"_"$scenario".out
    done
done

如果您不知道机构和场景名称,您可以对所有文件运行此操作并从文件名中提取它们(只要您的名称不包含空格):

for f in *; do echo "${f/_*} ${f##*_}"; done | 
    sort -u | while read ins sce; do 
        paste "$ins"_*_"$sce"* > "$ins"_"$sce".out
    done

答案2

如果文件都在同一个目录中,您可以:

ls |
awk -F_ '{ i=$1; m=$2; s=$3; f[i"_"s] = f[i"_"s] " " $0 }
         END{ for(insc in f)
                printf "paste%s >out_%s.txt\n",f[insc],insc
         }'

它将文件名拆分为“_”(-F_),将变量 i、m、s 设置为文件名的前 3 个部分(研究所、模型、场景),并在数组 f 中累积文件名。该数组仅由研究所和场景索引,因此所有模型都连接在一起(不使用 m)。最后的 END 打印 f 数组,并使用索引(研究所_场景)作为输出文件的名称。使用您的示例,这将产生

paste wbm_gfdl_rcp8p5_mississippi.txt wbm_hadgem_rcp8p5_mississippi.txt >out_wbm_rcp8p5.txt
paste matsiro_hadgem_rcp4p5_mississippi.txt matsiro_ipsl_rcp4p5_mississippi.txt >out_matsiro_rcp4p5.txt
paste matsiro_gfdl_rcp8p5_mississippi.txt matsiro_miroc_rcp8p5_mississippi.txt >out_matsiro_rcp8p5.txt

然后您需要将其导入到 shell 中以执行它。添加| sh到上面的最后一行即可执行此操作。


要从输入文件中删除某些列,您需要修改收集所有输入文件名的 awk 行。在第一行 awk 中:

{ i=$1; m=$2; s=$3; f[i"_"s] = f[i"_"s] " " $0 }

文件名是“$0”。例如,如果你将此行更改为:

{ i=$1; m=$2; s=$3; f[i"_"s] = f[i"_"s] sprintf(" <(cut -f4 %s)",$0) }

然后您将获得示例输出:

paste <(cut -f4 wbm_gfdl_rcp8p5_mississippi.txt) <(cut -f4 wbm_hadgem_rcp8p5_mississippi.txt) >out_wbm_rcp8p5.txt

但如果您只想剪切第二个文件名,那就有点复杂了,您需要这样做:

{ i=$1; m=$2; s=$3; 
  if(f[i"_"s]=="")add = $0; else add = sprintf("<(cut -f4 %s)",$0);
  f[i"_"s] = f[i"_"s] " " add }

所以你会得到

paste wbm_gfdl_rcp8p5_mississippi.txt <(cut -f4 wbm_hadgem_rcp8p5_mississippi.txt) >out_wbm_rcp8p5.txt

如果sh不明白语法<(cut ...)则用 替换它bash

答案3

也许可以使用 ls 命令。类似的东西ls $institute_*_$scenario_*.txt应该返回具有相同机构和场景的所有文件。

相关内容