将文件中的列读入变量并用于另一个文件中的替换值

时间:2016-02-08 06:50:54

标签: bash shell awk sed gawk

我有以下文件: input.txt中

b73_chr10   w22_chr9
w22_chr7    w22_chr10
w22_chr8    w22_chr8

我编写了以下代码(如下所示)来读取第一列和第二列,并将第一列的值替换为output.conf文件中第二列中的值。例如,我想将值更改为b73_chr10 w22_chr9,w22_chr7与w22_chr10,w22_chr8与w22_chr8并继续执行所有值直到结束。

value1=$(echo $line| awk -F\ '{print $1}' input.txt)
value2=$(echo $line| awk -F\ '{print $2}' input.txt)
sed -i '.bak' 's/$value1/$value2/g' output.conf 
cat output.conf

output.conf

    <rules>
    <rule>
    condition =between(b73_chr10,w22_chr1)
    color = ylgn-9-seq-7
    flow=continue
    z=9
    </rule>
    <rule>
    condition =between(w22_chr7,w22_chr2)
    color = blue
    flow=continue
    z=10
    </rule>
    <rule>
    condition =between(w22_chr8,w22_chr3)
    color = vvdblue
    flow=continue
    z=11
    </rule>
    </rules>

我尝试了命令(如上所述),但是它留给我的空白文件。可以指导哪里出错了吗?

2 个答案:

答案 0 :(得分:2)

我怀疑sed本身就是错误的工具。但是,您可以单独使用bash执行的操作:

#!/usr/bin/env bash

# Declare an associative array (requires bash 4)
declare -A repl=()

# Step through our replacement file, recording it to an array.
while read this that; do
  repl["$this"]="$that"
done < inp1

# Read the input file, replacing things strings noted in the array.
while read line; do
  for string in "${!repl[@]}"; do
    line="${line/$string/${repl[$string]}}"
  done
  echo "$line"
done < circos.conf

这种方法当然过于简单,因此不应逐字使用 - 您要确保只编辑您真正想要编辑的行(验证它们是否匹配)例如/condition =between/。请注意,因为此解决方案使用关联数组(declare -A ...),所以它取决于bash版本4.

如果你用awk解决这个问题,同样的基本原则也适用:

#!/usr/bin/awk -f

# Collect the tranlations from the first file.
NR==FNR { repl[$1]=$2; next }

# Step through the input file, replacing as required.
{
  for ( string in repl ) {
    sub(string, repl[string])
  }
}

# And print.
1

你运行它的第一个参数是翻译文件,第二个参数是输入文件:

$ ./thisscript translations.txt circos.conf

答案 1 :(得分:2)

在你阅读更好的解决方案之前,先解释一下你做错了什么 您的脚本的固定版本将是

while read -r line; do
   value1=$(echo "$line"| awk -F" "  '{print $1}')
   value2=$(echo "$line"| awk -F" "  '{print $2}')
   sed -i "s/$value1/$value2/g" circos.conf 
done < input.txt

这里有什么变化?

  • 添加了while read -r line; do ... done < input.txt
    您的"$line"从未初始化
  • awk with -F&#34; &#34;而不是\;
  • 之间有空格
  • awk没有input.txt
    awk应该从管道读取,而不是从文件中读取
  • 用双引号打开 必须评估变量。

这个解决方案有什么问题?
首先,您必须希望input.txt中的值是sed_friendly(没有斜杠或其他特殊字符)。 当你将它用于大文件时,你将继续循环。 awk可以处理循环,你应该避免在循环中嵌入awk。

当input.txt受限时,您可能需要类似

的内容
sed -i -e 's/b73_chr10/w22_chr9/g' \
       -e 's/w22_chr7/w22_chr10/g' \
       -e 's/w22_chr8/w22_chr8/g' circos.conf

现在@alvits的评论很有意义。将所有这些sed命令放在sed-command文件中。如果你不能改变input.txt的格式,你可以在脚本中重写它,但是在@Ghoti的解决方案中使用数组会更好。