【问题标题】:Looping of the files based on the keyword根据关键字循环文件
【发布时间】:2017-12-15 11:37:29
【问题描述】:

我有一个包含文件的文件夹。每个文件的名称可以分为三个部分:名称 - 所有文件都相同; key - 一些关键字,根据这些关键字可以将文件分为 3 组;结束编号 (1..10) - 组内的位置。示例:

  • 第一组文件,由“key 1”定义

    name_key1_1
    name_key1_2
    name_key1_3
    ..
    name_key1_10
    
  • 第二组文件,由“key 2”定义

    name_key2_1
    name_key2_2
    name_key2_3
    ..
    name_key2_10
    
  • 第三组文件,由“key 3”定义

    name_key3_1
    name_key3_2
    name_key3_3
    ..
    name_key3_10
    

现在我需要循环所有文件,以便将它们传递给某个程序,该程序将同一组(键)中的文件组合在一起。每次我只需要使用相同的密钥传递文件才能将它们组合在一起(避免在每次处理期间将文件与其他密钥混合)。因此有 3 组文件,应使用以下方法创建三个组合文件:

for file in ${input}/*.xtc; do
 file_name=$(basename "$file")
 prog  -f ${input}/${name}_${key}_* -o ${output}/${name}_${key}_combined.xtc -cat
done

在此示例中,通过执行 prog,我需要组合每个组中的 10 个文件(使用相同的键),避免与另一个组中的文件混合。

我将感谢一个实现此工作流程及其应用过滤器的示例,例如基于从文件名称中自动检测到的组的数量。

【问题讨论】:

  • <h1> 的标题刺痛了我的眼睛 :(
  • 然后edit,这就是 Stack Overflow 的工作原理!

标签: bash file loops


【解决方案1】:

如果字段由下划线分隔,并且值中没有额外的下划线(即所有文件名都包含两个下划线),则只需使用下划线拆分。

for file in ${input}/*.xtc; do
    oldIFS=$IFS
    IFS=_
    set -- ${file#"$input"/}
    IFS=$oldIFS
    dest="${output}/${1}_${2}_combined.xtc"
    test -e "$dest" && continue
    prog  -f "${input}/${1}_${2}_"{1..10} -o "$dest" -cat
done

命令set -- stringstring 拆分为$IFS 的值,并用结果填充位置参数$1$2$3 等。参数扩展 ${variable#prefix} 返回 $variable 的值,删除了 prefix(如果找到)。

我们粗暴地循环遍历所有文件,但如果输出文件已经存在,则跳过prog

如果您需要从末尾剥离下划线,可能在循环内这样:

     base=${file%_*}
     tail=${file#"$base"}
     head=${base%_"$tail"}
     dest="$outputdir/${head#$input/}_combined.txt"
     test -e "$dest" && continue
     :

${variable#suffix} 删除后缀。

如果您可以重新设计输入的结构,使组(可能还有它们之前的名称)成为子目录,这将使处理集合变得非常自然和直接,而无需任何额外的逻辑。

【讨论】:

  • 请注意,在许多语言环境中,10 将排在 2 之前。你能改变它,使集合从 0 到 9 编号,或者用前导零填充个位数的数字吗?我用大括号扩展 {1..10} 解决了这个问题,但这有点碍眼。
【解决方案2】:

我建议使用以下代码,假设循环时 ${name} 不会改变。

/编辑: 由于@tripleee 是对的,我们应该使用 find 而不是 ls

#!/bin/bash
input="/tmp/test/"
output="/tmp/"
name="foo"
for key in $(find ${input} -maxdepth 1 -mindepth 1 -type f -printf "%f\n" | rev| cut -d"_" -f2 | rev | sort | uniq ); do 
    for file in $(find ${input} -maxdepth 1 -mindepth 1 -type f -name \*_${key}_\* -print | sort ); do
        prog  -f ${file} -o ${output}/${name}_${key}_combined.xtc -cat
    done
done
  1. 在输入目录中查找所有文件。
  2. 从文件名中提取倒数第​​二个字段(也就是关键字);
  3. 对所有关键字进行排序并仅打印一次。
  4. 为每个关键字查找包含该关键字的文件。
  5. 将该文件传递给您的程序。
  6. 完成。

【讨论】:

  • @tripleee 你是对的。我已经编辑了脚本以满足您的建议。
  • 如果是单个目录,那么printf '%s\n' "$input"/* | cut -d_ -f2 就足够了。 cut 无论如何都会删除目录,您可以避免在内部循环中同时使用 findsort。但我并不特别相信这是 OP 想要的。问题不清楚。
  • 用下划线分割字段是个好主意,但我刚刚发现名称中也有几个下划线,例如 AT1R_ss_charmm_tension_NPT_parinel_long_1.0bar_2.xtc 这里 AT1R_ss_charmm_tension_NPT_parinel_long 是名称 l1.0bar 是关键字和带有此关键字的文件数中的_2
  • 能否请您edit您的问题以更现实的要求对其进行更新?
  • 我已经更新了我的答案。现在通过搜索倒数第二个字段同时用下划线分割文件来找到关键字。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-18
  • 1970-01-01
相关资源
最近更新 更多