用 awk 变量替换

用 awk 变量替换

基本上,我需要复制并替换$1(在cat文件之后)到sample变量中,以便将其替换为地址/disk1/ngsep/"$sample"/"$1"_bowtie2_readpos.stats。这是我的尝试:

cat samples_long.10ids.txt | awk -v sample="$1" '{gsub(/_USD.*/,"",sample); print $sample,$1}'

其产生:

P2_142_USD16089440L_HJM27DSXX_L3 P2_142_USD16089440L_HJM27DSXX_L3
P2_144_USD16089441L_HJM27DSXX_L3 P2_144_USD16089441L_HJM27DSXX_L3
P2_145_USD16089442L_HJM27DSXX_L3 P2_145_USD16089442L_HJM27DSXX_L3
P2_168_USD16089450L_HJM27DSXX_L3 P2_168_USD16089450L_HJM27DSXX_L3
P2_171_USD16089451L_HJM27DSXX_L4 P2_171_USD16089451L_HJM27DSXX_L4
P2_172_USD16089452L_HJM27DSXX_L4 P2_172_USD16089452L_HJM27DSXX_L4
P2_188_USD16089456L_HJM27DSXX_L4 P2_188_USD16089456L_HJM27DSXX_L4
P2_262_USD16089477L_HJJNWDSXX_L2 P2_262_USD16089477L_HJJNWDSXX_L2
P2_270_USD16089479L_HJJNWDSXX_L2 P2_270_USD16089479L_HJJNWDSXX_L2
P2_271_USD16089480L_HJJNWDSXX_L4 P2_271_USD16089480L_HJJNWDSXX_L4

但是我需要:

P2_142 P2_142_USD16089440L_HJM27DSXX_L3
P2_144 P2_144_USD16089441L_HJM27DSXX_L3
P2_145 P2_145_USD16089442L_HJM27DSXX_L3
P2_168 P2_168_USD16089450L_HJM27DSXX_L3
P2_171 P2_171_USD16089451L_HJM27DSXX_L4
P2_172 P2_172_USD16089452L_HJM27DSXX_L4
P2_188 P2_188_USD16089456L_HJM27DSXX_L4
P2_262 P2_262_USD16089477L_HJJNWDSXX_L2
P2_270 P2_270_USD16089479L_HJJNWDSXX_L2
P2_271 P2_271_USD16089480L_HJJNWDSXX_L4

为了在更长的管道中使用它:

cat samples_long.10ids.txt | 
cat `awk -v sample="$1" 'BEGIN {gsub(/_USD.*/,"",sample); print "/disk1/ngsep/"$sample"/"$1"_bowtie2_readpos.stats"}'` | 
awk '{if(NR<151) {print $1,$2,$3,$4,$5,$3/$5*100} else {print $0}}' | 
less

更新

感谢@cas 的回答,我可以成功。我改变了更长的管道:

tail -n +1 `awk '{sample=$1; gsub(/_USD.*/,"",sample); print "/disk1/ngsep/"sample"/"$1"_bowtie2_readpos.stats"}' samples_long.10ids.txt` | awk 'm=($1 ~ /^[0-9]+$/) {print $0,$3/$5*100.0} !m {print $0}' | awk 'm=($1 == "==>") {save_location=$2} !m&&$1=="1",$1=="Bases" {print > save_location}'

解释:

首先,我有几个文件,位于不同的位置,格式如下:

1 44270430 2888669 939293704 101672177
2 39504262 2535442 939293704 101672177
3 36179652 2298760 939293704 101672177
4 35187362 2216378 939293704 101672177
5 31718310 1957024 939293704 101672177
...
145 30614327 2148102 939293704 101672177
146 31053766 2211019 939293704 101672177
147 33769500 2475193 939293704 101672177
148 34799685 2574711 939293704 101672177
149 38192883 2761700 939293704 101672177
150 41098709 2974392 939293704 101672177

Alignments      939293704       101672177
Bases   140205023688    15190431468

我想做一个运算,将第 3 列除以第 5 列,然后乘以 100,并将其保存为第 6 列。结果:

1 44270430 2888669 939293704 101672177 2.84116
2 39504262 2535442 939293704 101672177 2.49374
3 36179652 2298760 939293704 101672177 2.26095
4 35187362 2216378 939293704 101672177 2.17993
5 31718310 1957024 939293704 101672177 1.92484
...
145 30614327 2148102 939293704 101672177 2.11277
146 31053766 2211019 939293704 101672177 2.17465
147 33769500 2475193 939293704 101672177 2.43448
148 34799685 2574711 939293704 101672177 2.53237
149 38192883 2761700 939293704 101672177 2.71628
150 41098709 2974392 939293704 101672177 2.92547

Alignments      939293704       101672177
Bases   140205023688    15190431468

因此,让我解释一下更长的指令:

`awk '{sample=$1; gsub(/_USD.*/,"",sample); print "/disk1/ngsep/"sample"/"$1"_bowtie2_readpos.stats"}' samples_long.10ids.txt` |

这就是为什么我需要进行替换,以获得以samples_long.10ids.txt.每个文件都保存在名为例如 的目录中P2_142。结果:

/disk1/ngsep/P2_142/P2_142_USD16089440L_HJM27DSXX_L3_bowtie2_readpos.stats
/disk1/ngsep/P2_144/P2_144_USD16089441L_HJM27DSXX_L3_bowtie2_readpos.stats
/disk1/ngsep/P2_145/P2_145_USD16089442L_HJM27DSXX_L3_bowtie2_readpos.stats
/disk1/ngsep/P2_168/P2_168_USD16089450L_HJM27DSXX_L3_bowtie2_readpos.stats
/disk1/ngsep/P2_171/P2_171_USD16089451L_HJM27DSXX_L4_bowtie2_readpos.stats
...

tail -n +1:我使用它是因为我需要读取打印地址所针对的所有文件(在标准输出中)awk并添加它们各自的位置。结果:

==> /disk1/ngsep/P2_142/P2_142_USD16089440L_HJM27DSXX_L3_bowtie2_readpos.stats <==
1 37000568 2614993 747883433 76303046
2 33228316 2330791 747883433 76303046
...
149 33852828 2660530 747883433 76303046
150 36161756 2836045 747883433 76303046

Alignments      747883433       76303046
Bases   111613795461    11392665612

==> /disk1/ngsep/P2_144/P2_144_USD16089441L_HJM27DSXX_L3_bowtie2_readpos.stats <==
1 40000373 2754292 838333186 82982133
2 35955786 2451917 838333186 82982133
...

awk 'm=($1 ~ /^[0-9]+$/) {print $0,$3/$5*100.0} !m {print $0}' | 在这里,我通过仅当 $1 与数字匹配时才打印来进行操作,当不匹配时,只打印整行而不进行操作。结果:

==> /disk1/ngsep/P2_142/P2_142_USD16089440L_HJM27DSXX_L3_bowtie2_readpos.stats <==
1 37000568 2614993 747883433 76303046 3.42711
2 33228316 2330791 747883433 76303046 3.05465
...
149 33852828 2660530 747883433 76303046 3.48679
150 36161756 2836045 747883433 76303046 3.71682

Alignments      747883433       76303046
Bases   111613795461    11392665612

==> /disk1/ngsep/P2_144/P2_144_USD16089441L_HJM27DSXX_L3_bowtie2_readpos.stats <==
1 40000373 2754292 838333186 82982133 3.31914
2 35955786 2451917 838333186 82982133 2.95475
...

awk 'm=($1 == "==>") {save_location=$2} !m&&$1=="1",$1=="Bases" {print > save_location}' 进行操作后,我需要将每个相应的文件保存到特定目录。因此,当使用 时tail -n +1,它将==>和之间的文件位置附加<==到输出,然后我save_location通过分配给$2if将该位置保存在变量中$1=="==>"。如果没有,我将模式之间的其余部分保存1Bases指向的地址save_location。以示例对应的文件P2_142为例:

1 37000568 2614993 747883433 76303046 3.42711
2 33228316 2330791 747883433 76303046 3.05465
3 30544208 2130666 747883433 76303046 2.79237
4 29727794 2059047 747883433 76303046 2.69851
5 26873913 1825829 747883433 76303046 2.39287
...
145 27262253 2093226 747883433 76303046 2.74331
146 27992017 2188217 747883433 76303046 2.8678
147 30385435 2433407 747883433 76303046 3.18913
148 31218703 2514902 747883433 76303046 3.29594
149 33852828 2660530 747883433 76303046 3.48679
150 36161756 2836045 747883433 76303046 3.71682

Alignments      747883433       76303046
Bases   111613795461    11392665612

答案1

使用 sed 可以轻松完成此操作。

$ sed -E -e 's/^((.*)_USD.*)/\2 \1/' input.txt 
P2_142 P2_142_USD16089440L_HJM27DSXX_L3
P2_144 P2_144_USD16089441L_HJM27DSXX_L3
P2_145 P2_145_USD16089442L_HJM27DSXX_L3
P2_168 P2_168_USD16089450L_HJM27DSXX_L3
P2_171 P2_171_USD16089451L_HJM27DSXX_L4
P2_172 P2_172_USD16089452L_HJM27DSXX_L4
P2_188 P2_188_USD16089456L_HJM27DSXX_L4
P2_262 P2_262_USD16089477L_HJJNWDSXX_L2
P2_270 P2_270_USD16089479L_HJJNWDSXX_L2
P2_271 P2_271_USD16089480L_HJJNWDSXX_L4

该 sed 脚本使用两个捕获组,即由(和包围的正则表达式模式)。第一个是整个输入行,第二个是 之前的行的第一部分_USD。它将每个输入行替换为第二个捕获组 ( \2)、一个空格,然后替换为第一个捕获组 ( \1)。

或者与awk

awk -F'_' -e '{print $1 "_" $2 " " $0}' input.txt 

这将输入字段分隔符设置为_,然后(对于输入的每一行)它打印前两个字段,它们之间有一个下划线、一个空格,然后打印整个输入行。


您的命令存在几个问题:

cat samples_long.10ids.txt | \
  awk -v sample="$1" '{gsub(/_USD.*/,"",sample); print $sample,$1}'
  1. 你不需要 cat 将文件通过管道传输到 awk 中。 awk 可以读取命令行上作为参数给出的文件名。

  2. 您正在将 awk 变量设置sample为“$1”。我认为您指的是 awk 中的第一个字段,而不是某些(未显示的)shell 脚本包装器的第一个参数。那是行不通的。$1shell 中不存在awk 。它仅在 awk 读取一行输入数据时存在。

  3. 您还没有告诉 awk 使用什么作为字段分隔符,因此它默认为空白(空格和制表符)。在您的示例输入中,没有空格字符,因此 $1 是整个输入行(称为$0)。

  4. 您正在打印“$sample”。这告诉 awk 您要打印变量中包含的字段号sample

    sample 包含一个字符串,因此0在该上下文中计算为 -print $sample相当于printing $0.所以你的代码是有效的print $0 $1。这是有效的print $0 $0- 您将整行打印两次。

  5. 如果您想打印内容sample本身(而不是计算结果的字段编号sample),那么只需print sample.

  6. 第 4 点和第 5 点可能需要更多解释,或者至少需要一个更容易理解的示例。

    每次 awk 读取输入行时,它都会自动设置一个变量,该变量称为NF该行中的字段数。

    如果你想打印字段的数量,你只需打印NF。如果要打印字段编号等于 NF 的字段,请打印$NF(这将打印输入行的最后一个字段)。

    您还可以对 NF(它是一个整数)进行算术和其他运算。例如print $(NF-1)将打印倒数第二个字段。

    回到你的代码:你打印了$sample.在整数上下文中,sample有值0,因此您打印了$0,这是整个输入行。

  7. 考虑到上述所有内容,这将有效:

    awk '{sample=$1; gsub(/_USD.*/,"",sample); print sample,$1}' samples_long.10ids.txt
    

    但对于这样一个简单的任务来说,它过于复杂了。 awk 可以将输入拆分为由下划线分隔的字段,因此更容易做到这一点。

    awk -F'_' -e '{print $1 "_" $2 " " $0}' samples_long.10ids.txt
    

答案2

菜鸟awk错误...

awk将文件作为参数:

gawk [ POSIX 或 GNU 风格选项 ] [ -- ] 程序文本文件...

相关内容