用Unix文件中的另一个列表替换字符串列表的有效方法是什么?

时间:2011-08-25 22:47:57

标签: bash unix scripting file-io

假设我有两个字符串列表(列表A和列表B),每个列表中的条目数N完全相同,我想用A的第n个元素替换所有出现的A的第n个元素B在Unix中的文件中(理想情况下使用Bash脚本)。

最有效的方法是什么?

效率低下的方法是让N次调用“sed s/stringA/stringB/g”。

6 个答案:

答案 0 :(得分:9)

这将一次完成。它将listA和listB读入awk数组,然后对于linput的每一行,它检查每个单词,如果在listA中找到该单词,则该单词将被listB中的相应单词替换。

awk '
    FILENAME == ARGV[1] { listA[$1] = FNR; next }
    FILENAME == ARGV[2] { listB[FNR] = $1; next }
    {
        for (i = 1; i <= NF; i++) {
            if ($i in listA) {
                $i = listB[listA[$i]]
            }
        }
        print
    }
' listA listB filename > filename.new
mv filename.new filename

我假设listA中的字符串不包含空格(awk的默认字段分隔符)

答案 1 :(得分:6)

打电话给sed编写sed脚本,另一个使用它?如果您的列表位于listAlistB文件中,则为:

paste -d : listA listB | sed 's/\([^:]*\):\([^:]*\)/s%\1%\2%/' > sed.script
sed -f sed.script files.to.be.mapped.*

我正在对“单词”进行一些彻底的假设,不包含冒号或百分号,但你可以适应这一点。某些版本的sed具有可指定的命令数量的上限;如果这是一个问题,因为你的单词列表足够大,那么你可能必须将生成的sed脚本拆分为应用的单独文件 - 或者更改为使用没有限制的东西(例如Perl)。

需要注意的另一个项目是变化顺序。如果要交换两个单词,则需要仔细制作单词列表。通常,如果将(1)wordA映射到wordB并将(2)wordB映射到wordC,则重要的是sed脚本是否在映射(2)之前或之后进行映射(1)。

显示的脚本对字边界不小心;您可以通过各种方式对其进行审核,具体取决于您使用的sed版本以及您构成单词的标准。

答案 2 :(得分:2)

我需要做类似的事情,然后根据地图文件生成sed命令:

$ cat file.map
abc => 123
def => 456
ghi => 789

$ cat stuff.txt
abc jdy kdt
kdb def gbk
qng pbf ghi
non non non
try one abc

$ sed `cat file.map | awk '{print "-e s/"$1"/"$3"/"}'`<<<"`cat stuff.txt`"
123 jdy kdt
kdb 456 gbk
qng pbf 789
non non non
try one 123

确保您的shell支持与您在地图中一样多的sed参数。

答案 3 :(得分:1)

这对Tcl来说相当简单:

set fA [open listA r]
set fB [open listB r]
set fin [open input.file r]
set fout [open output.file w]

# read listA and listB and create the mapping of corresponding lines
while {[gets $fA strA] != -1} {
    set strB [gets $fB]
    lappend map $strA $strB
}

# apply the mapping to the input file
puts $fout [string map $map [read $fin]]

# if the file is large, do it line by line instead
#while {[gets $fin line] != -1} {
#    puts $fout [string map $map $line]
#}

close $fA
close $fB
close $fin
close $fout

file rename output.file input.file

答案 4 :(得分:1)

您可以在bash中执行此操作。将列表放入数组中。

listA=(a b c)
listB=(d e f)
data=$(<file)
echo "${data//${listA[2]}/${listB[2]}}" #change the 3rd element. Redirect to file where necessary

答案 5 :(得分:-1)

使用tr(1)(翻译或删除字符):

 cat file | tr 'abc' 'XYZ' > file_new
 mv file_new file