如何在cut命令

时间:2017-11-07 17:49:14

标签: bash environment-variables cut

我有一个包含2列的文件,我想使用第二列中的值来设置cut命令中的范围,以从另一个文件中选择一系列字符。我想要的范围是第二列中值的位置加上接下来的10个字符的字符。我会在一段时间内给出一个例子。

我的文件是这样的:

包含2列并且行之间没有空白行的文件( file1.txt ):

NAME1 10
NAME2 25
NAME3 48
NAME4 66

我想要提取可变字符范围的文件(只有一个很长的行,没有空格,没有粗体字)( file2.txt ):

  

GATCGAGCGG的 GATTCTTTTT TTTTA的 GGCGAGTCAG CTAGCATCAGCTA的 CGAGAGGCGA GGGCGGGC的 TATCACGACT ACGACTACGACTACAGCATCAGCATCAGCGCACTAGAGCGAGGCTAGCTAGCTACGACTACGATCAGCATCGCACATCGACTACGATCAGCATCAGCTACGCATCGAAGAGAGAGC

......或更确切地说(用于复制/粘贴测试):

GATCGAGCGGGATTCTTTTTTTTTAGGCGAGTCAGCTAGCATCAGCTACGAGAGGCGAGGGCGGGCTATCACGACTACGACTACGACTACAGCATCAGCATCAGCGCACTAGAGCGAGGCTAGCTAGCTACGACTACGATCAGCATCGCACATCGACTACGATCAGCATCAGCTACGCATCGAAGAGAGAGC

所需的结果文件,每行一个序列( result.txt ):

GATTCTTTTT
GGCGAGTCAG
CGAGAGGCGA
TATCACGACT

生成的文件将包含10-20,25-35,48-58和66-76中的字符,每个范围都在一个新行中。因此,它始终保持10的范围,但在不同的起点和那些起点由第一个文件的第二列中的值设置。

我尝试了命令:

for i in $(awk '{print $2}' file1.txt);
do
        p1=$i;
        p2=`expr "$1" + 10`
        cut -c$p1-$2 file2.txt > result.txt;
done

我没有收到任何输出或错误消息。

我也尝试过:

while read line; do
    set $line
    p2=`expr "$2" + 10`
    cut -c$2-$p2 file2.txt > result.txt;
done <file1.txt

这最后一个命令给出了一条错误消息:

cut: invalid range with no endpoint: -
Try 'cut --help' for more information.
expr: non-integer argument

4 个答案:

答案 0 :(得分:4)

这里不需要cut; dd可以完成索引到文件的工作,并只读取您想要的字节数。 (请注意,status=none是一个GNUism;您可能需要将其保留在其他平台上并重定向stderr,否则如果您想要禁止信息日志记录)。

while read -r name index _; do
  dd if=file2.txt bs=1 skip="$index" count=10 status=none
  printf '\n'
done <file1.txt >result.txt

这种方法避免了过多的内存需求(在读取整个file2时存在 - 假设它很大),并且具有有限的性能要求(开销等于启动{{1的一个副本)每个序列提取)。

答案 1 :(得分:3)

使用 awk

$ awk 'FNR==NR{a=$0; next} {print substr(a,$2+1,10)}' file2 file1
GATTCTTTTT
GGCGAGTCAG
CGAGAGGCGA
TATCACGACT

答案 2 :(得分:2)

如果file2.txt不是太大,那么你可以在内存中读取它, 并使用Bash子字符串来提取所需的范围:

data=$(<file2.txt)
while read -r name index _; do
  echo "${data:$index:10}"
done <file1.txt >result.txt

这比为每个范围定义运行cut或其他进程更有效。

(感谢@CharlesDuffy提示阅读data ,而无用的catwhile循环。)

答案 3 :(得分:0)

解决问题的一种方法:

#!/bin/bash                                                                                                        

while read line; do
    pos=$(echo "$line" | cut -f2 -d' ')
    x=$(head -c $(( $pos + 10 )) file2.txt | tail -c 10)
    echo "$x"
done < file1.txt > result.txt

这不是经验丰富的bash黑客会使用的解决方案,但对于那些不熟悉bash的人来说这是非常好的。它使用的工具非常通用,但如果你需要高性能则有些不好。 Shell脚本通常被很少使用shell脚本的人使用,但是他们知道一些命令而只是想完成工作。这就是为什么我要包含这个解决方案的原因,即使其他答案对于经验丰富的人来说也是优越的。

第一行非常简单。它只是从file1.txt中提取数字。第二行使用非常好的工具headtail。通常,它们与行而不是字符一起使用。不过,我使用pos + 10打印了第一个head个字符。结果通过管道输入tail,打印出最后10个字符。

感谢@CharlesDuffy的改进。