我有一个这样的文件:
id target_id length eff_length
1 intron_FBgn0000721:20_FBgn0000721:18 1136 243.944268
1 intron_FBgn0000721:19_FBgn0000721:18 1122 240.237419
2 intron_FBgn0264373:2_FBgn0264373:3 56 0
3 intron_FBgn0027570:4_FBgn0027570:3 54 0
对于第二列target_id
,我只想保留第一列和第二列FBgnXXXX
之间的字符串(并非总是如此,有时是其他名称)。因此,新的输出文件第 2 列的值将更简单,但文件的其余部分保持不变。intron_
:
我尝试使用 sed 命令,但不知道如何删除我不需要的部分。
答案1
使用sed
和column
:
$ sed -E 's/ intron_([^:]*):[^[:space:]]*/ \1/' file | column -t
id target_id length eff_length
1 FBgn0000721 1136 243.944268
1 FBgn0000721 1122 240.237419
2 FBgn0264373 56 0
其中的关键部分是替换命令:
s/ intron_([^:]*):\S*/ \1/
它查找第一个冒号intron_
之后和之前的所有内容并将其保存intron_
到变量中1
。 [^[:space:]]*
匹配从冒号到字段末尾的所有内容。所有这些都被变量中保存的文本替换1
。
awk
与制表符分隔的输出一起使用:
$ awk -v "OFS=\t" '{$2=$2;sub(/intron_/, "", $2); sub(/:.*/, "", $2); print}' file
id target_id length eff_length
1 FBgn0000721 1136 243.944268
1 FBgn0000721 1122 240.237419
2 FBgn0264373 56 0
解释:
-v "OFS=\t"
这将输出字段分隔符设置为制表符。这有助于排列列,但可能
column
没有必要。$2=$2
打印一行时,
awk
不会更改为我们新指定的输出字段分隔符,除非我们更改该行上的某些内容。将第二个字段分配给第二个字段足以确保输出具有制表符。sub(/intron_/, "", $2)
这
intron_
将从第二个字段中删除。sub(/:.*/, "", $2)
这将从第二个字段中删除第一个冒号之后的所有内容。
print
这将打印我们的新行。
awk
与自定义列格式一起使用
这与上面的类似,但使用printf
这样我们就可以根据需要自定义列宽和对齐方式的格式:
$ awk '{sub(/intron_/, "", $2); sub(/:.*/, "", $2); printf "%-3s %-12s %8s %3s\n",$1,$2,$3,$4}' file
id target_id length eff_length
1 FBgn0000721 1136 243.944268
1 FBgn0000721 1122 240.237419
2 FBgn0264373 56 0
这里的语句printf "%-3s %-12s %8s %3s\n",$1,$2,$3,$4
以通常的样式选择列宽和对齐方式printf
。
使用sed
制表符分隔并将其转换为逗号分隔
$ sed -E 's/ intron_([^:]*):[^[:space:]]*/ \1/; s/[[:space:]][[:space:]]*/,/g' file
id,target_id,length,eff_length
1,FBgn0000721,1136,243.944268
1,FBgn0000721,1122,240.237419
2,FBgn0264373,56,0
答案2
您可以使用perl
:
$ perl -anle '
BEGIN {$" = "\t"}
print "@{[@F]}" and next if $. == 1;
$F[1] = $1 if /_([^:]*):/;
print "@{[@F]}";
' file
id target_id length eff_length
1 FBgn0000721 1136 243.944268
1 FBgn0000721 1122 240.237419
2 FBgn0264373 56 0
3 FBgn0027570 54 0
解释
-a
:自动将每一行分割成数组@F
。BEGIN {$" = "\t"}
:我们将列表分隔符设置为 tab\t
,当在双引号字符串中插入数组或数组切片时使用它。print "@{[@F]}" and next if $. == 1
:我们打印标题,处理到下一行。$F[1] = $1 if /_([^:]*):/
_
:我们获取第一个 和之间的值:
,将其保存到 中的第二个元素@F
。print "@{[@F]}"
:只需打印所需的输出即可。
答案3
sed -e 'h;s/.*intron_[^:]*\(:[^[:space:]]*\).*/\1/;s/./ /g;;G;;s/\(.*\)\n\(.*\)intron_\([^:]*\):[^[:space:]]*/\2\3\1/' YourFile
在 1 sed(无管道)中保留列。它使用保持缓冲区
Posix 版本(--posix
GNU sed 也是如此)