如何在 cut 命令中循环变量范围
How to loop a variable range in cut command
我有一个包含 2 列的文件,我想使用第二列中的值将剪切命令中的范围设置为 select 来自另一个文件的字符范围。我想要的范围是第二列中值所在位置的字符加上接下来的 10 个字符。一会儿我会举个例子。
我的文件是这样的:
包含 2 列且行与行之间没有空行的文件 (file1.txt):
NAME1 10
NAME2 25
NAME3 48
NAME4 66
我要提取可变字符范围的文件(只有很长的一行,没有空格,没有粗体)(file2.txt):
GATCGAGCGGGATTCTTTTTTTTTAGGCGAGTCAGCTAGCATCAGCTACGAGAGGCGAGGGCGGGCTATCACGACTACGACTACGACTACAGCATCAGCATCAGCGCACTAGAGCGAGGCTAGCTAGCTACGACTACGATCAGCATCGCACATCGACTACGATCAGCATCAGCTACGCATCGAAGAGAGAGC
...或者,更直白地说(用于 copy/paste 测试):
GATCGAGCGGGATTCTTTTTTTTTAGGCGAGTCAGCTAGCATCAGCTACGAGAGGCGAGGGCGGGCTATCACGACTACGACTACGACTACAGCATCAGCATCAGCGCACTAGAGCGAGGCTAGCTAGCTACGACTACGATCAGCATCGCACATCGACTACGATCAGCATCAGCTACGCATCGAAGAGAGAGC
想要的结果文件,每行一个序列(result.txt):
GATTCTTTTT
GGCGAGTCAG
CGAGAGGCGA
TATCACGACT
生成的文件将包含 10-20、25-35、48-58 和 66-76 中的字符,每个范围占一行。因此,它将始终保持 10 的范围,但在不同的起点,这些起点由第一个文件第二列中的值设置。
我试过命令:
for i in $(awk '{print }' file1.txt);
do
p1=$i;
p2=`expr "" + 10`
cut -c$p1- file2.txt > result.txt;
done
我没有收到任何输出或错误消息。
我也试过:
while read line; do
set $line
p2=`expr "" + 10`
cut -c-$p2 file2.txt > result.txt;
done <file1.txt
最后一条命令给我一条错误消息:
cut: invalid range with no endpoint: -
Try 'cut --help' for more information.
expr: non-integer argument
这里不需要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
时出现的那样 - 假设它很大),并且具有有限的性能要求(开销等于启动 dd
的一个副本每个要提取的序列)。
一种解决方法:
#!/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
中提取数字。第二行使用了非常好的工具 head
和 tail
。通常,它们与行而不是字符一起使用。不过,我用 head
打印前 pos + 10
个字符。结果通过管道传输到 tail
中,打印最后 10
个字符。
感谢@CharlesDuffy 的改进。
如果file2.txt
不是太大,那么可以内存读取,
并使用 Bash 个子字符串来提取所需的范围:
data=$(<file2.txt)
while read -r name index _; do
echo "${data:$index:10}"
done <file1.txt >result.txt
对于每个范围定义,这将比 运行 cut
或其他过程更有效。
(感谢 @CharlesDuffy 提供阅读 data
没有 无用 cat
和 while
循环的提示.)
使用 awk
$ awk 'FNR==NR{a=[=10=]; next} {print substr(a,+1,10)}' file2 file1
GATTCTTTTT
GGCGAGTCAG
CGAGAGGCGA
TATCACGACT
我有一个包含 2 列的文件,我想使用第二列中的值将剪切命令中的范围设置为 select 来自另一个文件的字符范围。我想要的范围是第二列中值所在位置的字符加上接下来的 10 个字符。一会儿我会举个例子。
我的文件是这样的:
包含 2 列且行与行之间没有空行的文件 (file1.txt):
NAME1 10
NAME2 25
NAME3 48
NAME4 66
我要提取可变字符范围的文件(只有很长的一行,没有空格,没有粗体)(file2.txt):
GATCGAGCGGGATTCTTTTTTTTTAGGCGAGTCAGCTAGCATCAGCTACGAGAGGCGAGGGCGGGCTATCACGACTACGACTACGACTACAGCATCAGCATCAGCGCACTAGAGCGAGGCTAGCTAGCTACGACTACGATCAGCATCGCACATCGACTACGATCAGCATCAGCTACGCATCGAAGAGAGAGC
...或者,更直白地说(用于 copy/paste 测试):
GATCGAGCGGGATTCTTTTTTTTTAGGCGAGTCAGCTAGCATCAGCTACGAGAGGCGAGGGCGGGCTATCACGACTACGACTACGACTACAGCATCAGCATCAGCGCACTAGAGCGAGGCTAGCTAGCTACGACTACGATCAGCATCGCACATCGACTACGATCAGCATCAGCTACGCATCGAAGAGAGAGC
想要的结果文件,每行一个序列(result.txt):
GATTCTTTTT
GGCGAGTCAG
CGAGAGGCGA
TATCACGACT
生成的文件将包含 10-20、25-35、48-58 和 66-76 中的字符,每个范围占一行。因此,它将始终保持 10 的范围,但在不同的起点,这些起点由第一个文件第二列中的值设置。
我试过命令:
for i in $(awk '{print }' file1.txt);
do
p1=$i;
p2=`expr "" + 10`
cut -c$p1- file2.txt > result.txt;
done
我没有收到任何输出或错误消息。
我也试过:
while read line; do
set $line
p2=`expr "" + 10`
cut -c-$p2 file2.txt > result.txt;
done <file1.txt
最后一条命令给我一条错误消息:
cut: invalid range with no endpoint: -
Try 'cut --help' for more information.
expr: non-integer argument
这里不需要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
时出现的那样 - 假设它很大),并且具有有限的性能要求(开销等于启动 dd
的一个副本每个要提取的序列)。
一种解决方法:
#!/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
中提取数字。第二行使用了非常好的工具 head
和 tail
。通常,它们与行而不是字符一起使用。不过,我用 head
打印前 pos + 10
个字符。结果通过管道传输到 tail
中,打印最后 10
个字符。
感谢@CharlesDuffy 的改进。
如果file2.txt
不是太大,那么可以内存读取,
并使用 Bash 个子字符串来提取所需的范围:
data=$(<file2.txt)
while read -r name index _; do
echo "${data:$index:10}"
done <file1.txt >result.txt
对于每个范围定义,这将比 运行 cut
或其他过程更有效。
(感谢 @CharlesDuffy 提供阅读 data
没有 无用 cat
和 while
循环的提示.)
使用 awk
$ awk 'FNR==NR{a=[=10=]; next} {print substr(a,+1,10)}' file2 file1
GATTCTTTTT
GGCGAGTCAG
CGAGAGGCGA
TATCACGACT