【问题标题】:store txt files separately for each subcategories为每个子类别分别存储 txt 文件
【发布时间】:2014-09-30 17:15:36
【问题描述】:

我有几个实验。每个实验都有几个复制文件。我想通过以下方式将所有这些复制文件放入一个文本文件中。

假设有 3 个实验,每个实验有 2 个复制文件。(实验和复制数可以多于此)

/home/data/study1/EXP1_30/EXP1_replicate_1_30.txt
/home/data/study1/EXP1_30/EXP1_replicate_2_30.txt
/home/data/study1/EXP1_60/EXP1_replicate_1_60.txt
/home/data/study1/EXP1_60/EXP1_replicate_2_60.txt
/home/data/study1/EXP2_30/EXP2_replicate_1_30.txt
/home/data/study1/EXP2_30/EXP2_replicate_2_30.txt
/home/data/study1/EXP2_60/EXP2_replicate_1_60.txt
/home/data/study1/EXP2_60/EXP2_replicate_2_60.txt
/home/data/study1/EXP3_30/EXP3_replicate_1_30.txt
/home/data/study1/EXP3_30/EXP3_replicate_2_30.txt
/home/data/study1/EXP3_60/EXP3_replicate_1_60.txt
/home/data/study1/EXP3_60/EXP3_replicate_2_60.txt

输出 file1.txt 看起来像

/home/data/study1/EXP1/EXP1_replicate_1_30.txt,/home/data/study1/EXP1/EXP1_replicate_2_30.txt \
/home/data/study1/EXP2/EXP2_replicate_1_30.txt,/home/data/study1/EXP2/EXP2_replicate_2_30.txt \
/home/data/study1/EXP3/EXP3_replicate_1_30.txt,/home/data/study1/EXP3/EXP3_replicate_2_30.txt

输出 file2.txt 看起来像

/home/data/study1/EXP1/EXP1_replicate_1_60.txt,/home/data/study/EXP1/EXP1_replicate_2_60.txt \
/home/data/study1/EXP2/EXP2_replicate_1_60.txt,/home/data/study1/EXP2/EXP2_replicate_2_60.txt \
/home/data/study1/EXP3/EXP3_replicate_1_60.txt,/home/data/study1/EXP3/EXP3_replicate_2_60.txt

....

我的带有 for 循环的代码:

ID=(30 60)
exp=("EXP1" "EXP2" "EXP3")

d=""
for  txtfile in /home/data/study1/${exp[0]}/${exp[0]}*_${ID[0]}.txt
do
    printf "%s%s" "$d" "$txtfile" 
    d=","
done
printf " \\" 
printf "\n" 

d=""
for txtfile in /home/data/study1/${exp[1]}/${exp[1]}*_${ID[0]}.txt
do

    printf "%s%s" "$d" "$txtfile" 
    d=","
done
printf " \\" 
printf "\n" 

d=""
for txtfile in /home/data/study1/${exp[2]}/${exp[2]}*_${ID[0]}.txt
do

    printf "%s%s" "$d" "$txtfile" 
    d=","
done          

我为每个实验和复制都使用带有索引号的 for 循环,这非常耗时。有什么简单的方法吗?

【问题讨论】:

  • 如果你想要那个输出,为什么你的实验首先输出那些文件?
  • @hek2mgl 那些输出文件来自另一个管道,我必须根据这些特定格式的 ID 一起处理所有文件
  • 我永远无法理解为什么科学程序会产生科学家无法使用的输出,除非经过后处理。
  • 您不能更改(或其他人)更改进程的输出以生成可以被许多不同应用程序轻松读取的文件吗?您不能将结果存储在数据库中吗?至少后者应该是正确的,有来自问题的信息。
  • @hek2mgl 不,它是一个众所周知的管道,许多其他科学家都在使用它,但我正在处理的研究要求我以不同的方式处理数据,这就是为什么我不能改变管道的方式已实施。

标签: bash


【解决方案1】:

您还可以使用子shell 并从命令行(dat/experiment.txt 中的数据)执行此操作:

$ ( first=0; cnt=0; grep 30 dat/experiment.txt | sort | while read line; do \
[ "$first" = 0 ] && first=1 || { [ "$cnt" = 0 ] && echo ' \'; }; echo -n $line; \
((cnt++)); [ "$cnt" = 1 ] && echo -n ","; [ "$cnt" = 2 ] && cnt=0; done; \
echo "" ) >outfile1.txt

$ ( first=0; cnt=0; grep 60 dat/experiment.txt | sort | while read line; do \
[ "$first" = 0 ] && first=1 || { [ "$cnt" = 0 ] && echo ' \'; }; echo -n $line; \
((cnt++)); [ "$cnt" = 1 ] && echo -n ","; [ "$cnt" = 2 ] && cnt=0; done; \
echo "" ) >outfile2.txt

诚然,一个班轮最终比最初预期的要长,以匹配您的线路延续-完全是。如果您在输出文件中省略行继续,则该行减少为(例如):

$ (cnt=0; grep 30 dat/experiment.txt | sort | while read line; do echo -n $line; \
((cnt++)); [ "$cnt" = 1 ] && echo -n ","; [ "$cnt" = 2 ] && echo "" && cnt=0; \ 
done ) >outfile1.txt

输出:

$ cat outfile1.txt
/home/data/study1/EXP1_30/EXP1_replicate_1_30.txt,/home/data/study1/EXP1_30/EXP1_replicate_2_30.txt \
/home/data/study1/EXP2_30/EXP2_replicate_1_30.txt,/home/data/study1/EXP2_30/EXP2_replicate_2_30.txt \
/home/data/study1/EXP3_30/EXP3_replicate_1_30.txt,/home/data/study1/EXP3_30/EXP3_replicate_2_30.txt \

$ cat outfile2.txt
/home/data/study1/EXP1_60/EXP1_replicate_1_60.txt,/home/data/study1/EXP1_60/EXP1_replicate_2_60.txt \
/home/data/study1/EXP2_60/EXP2_replicate_1_60.txt,/home/data/study1/EXP2_60/EXP2_replicate_2_60.txt \
/home/data/study1/EXP3_60/EXP3_replicate_1_60.txt,/home/data/study1/EXP3_60/EXP3_replicate_2_60.txt \

【讨论】:

    【解决方案2】:

    我认为这可以满足您的要求:

    #!/bin/bash
    
    ids=( 30 60 )
    dir=/home/data/study1
    
    # join glob on comma, add slash at end
    # modified from http://stackoverflow.com/a/3436177/2088135
    join() { local IFS=,; echo "$* "'\'; } #' <- to fix syntax highlighting
    
    i=0
    for id in "${ids[@]}"; do
        s=$(for exp in "$dir"/EXP*"$id"; do join "$exp/"*"$id".txt; done)
        # trim off final slash and output to file
        echo "${s%?}" > file$((++i)).txt
    done
    

    输出(注意,测试的时候我设置了dir=.):

    $ cat file1.txt 
    ./EXP1_30/EXP1_replicate_1_30.txt,./EXP1_30/EXP1_replicate_2_30.txt \
    ./EXP2_30/EXP2_replicate_1_30.txt,./EXP2_30/EXP2_replicate_2_30.txt \
    ./EXP3_30/EXP3_replicate_1_30.txt,./EXP3_30/EXP3_replicate_2_30.txt 
    $ cat file2.txt 
    ./EXP1_60/EXP1_replicate_1_60.txt,./EXP1_60/EXP1_replicate_2_60.txt \
    ./EXP2_60/EXP2_replicate_1_60.txt,./EXP2_60/EXP2_replicate_2_60.txt \
    ./EXP3_60/EXP3_replicate_1_60.txt,./EXP3_60/EXP3_replicate_2_60.txt
    

    【讨论】:

      【解决方案3】:

      您可以使用以下bash 脚本:

      #!/bin/bash 
      
      i=0; n=0; files=""
      sort -t_ -k5 files.txt | while read line ; do
          files="$files $line"
          i=$((i+1))
          if [ $((i%6)) -eq 0 ] ; then
              n=$((n+1))
              cat $files > "$n.txt"
              files=""
          fi
      done
      

      【讨论】:

      • 我猜你选择了更便携的方法,但以防万一你还没有意识到(并且可能为了 OP 的利益),bash 允许你使用 files+="$line" (( i += 1))((++i))(( i % 6 == 0 ))
      • 是的,我在给出答案时考虑到了便携性
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-10
      • 1970-01-01
      相关资源
      最近更新 更多