提问者:小点点

如何用另一个文本文件(OSX Sierra、bash)中的数字替换文本文件中的矩阵条目


如何通过行号替换文本文件中的整行

上面链接中的问题询问如何替换文本文件中的行。nakeer(从底部开始的第二个答案)提供了一个适合我作为Mac用户的答案:

sed -i '' -e 's/text-on-line-to-be-changed.*/text-to-replace-the=whole-line/' file-name

然而,我不知道如何根据我的特殊情况修改它。如果有人能给我指出正确的方向,我将不胜感激。

>

  • 我有很多文件。每个文件都包含这个矩阵,如下所示:

    12.345678    0.000000    0.000000    
     0.000000   12.345678    0.000000    
     0.000000    0.000000   12.345678
    

    我有一个包含一列数字的附加文件,例如:

    87.654321   
    18.765432    
    21.876543
    ...
    

    我想从(2)中列的每一行中取一个数字。我想用它来替换(1)中一个矩阵的非零值(保留零值)。所以第一个文件中的第一个矩阵应该如下所示:

    87.654321    0.000000    0.000000    
     0.000000   87.654321    0.000000    
     0.000000    0.000000   87.654321
    

    第二个文件中的第二个矩阵应使用“18.765432”作为其非零值。

    我在bash脚本方面没有经验,但到目前为止我有(其中ic是我在(1)中包含原始矩阵的文件,我将其复制到一个新目录中,我可以将该矩阵更改为(3)):

    #!/bin/bash
    
    let timesteps=20000
    for ((step=0; step <= timesteps ; step++))
    do
      mkdir $step/results
      cp ic $step/ic
    
      cat X >> X # <--Here I'd like to modify nakeer's expression. Any hints would be much appreciated.
    

    更新:

    1. 我已经设法启动并运行了Ed非常清晰的解决方案。然而,有一个问题。包含矩阵的文件(参见上面的(1))也包含其他数据。例如(在执行Ed的代码之前):
        12.345678    0.000000    0.000000    
         0.000000   12.345678    0.000000    
         0.000000    0.000000   12.345678
       0.5   
       abc.xyx 
       90
       900
       0.125
       90
       6
    

    Ed的代码成功地将矩阵中的12.345678更改为新值。但是,矩阵下方数字列表中的0.125也更改为该新值。我不希望0.125被更改。

    Ed在match后面的代码似乎使用数字的格式来识别要更改的数字,看起来0.125属于应该更改的数字类别。如果有人对如何从更改中排除0.125有任何想法,我将不胜感激!


  • 共2个答案

    匿名用户

    $ ls
    file1  file2  file3  numbers  tst.awk
    

    .

    $ cat tst.awk
    NR==FNR { a[NR]=$1; next }
    
    FNR==1 {
        close(out)
        out = FILENAME ".new"
        fileNr++
    }
    
    match($0,/[0-9.]+[1-9][0-9.]+/) {
        $0 = substr($0,1,RSTART-1) a[fileNr] substr($0,RSTART+RLENGTH)
    }
    
    { print > out }
    

    .

    $ tail -n +1 numbers file*
    ==> numbers <==
    87.654321
    18.765432
    21.876543
    
    ==> file1 <==
    12.345678    0.000000    0.000000
     0.000000   12.345678    0.000000
     0.000000    0.000000   12.345678
    
    ==> file2 <==
    12.345678    0.000000    0.000000
     0.000000   12.345678    0.000000
     0.000000    0.000000   12.345678
    
    ==> file3 <==
    12.345678    0.000000    0.000000
     0.000000   12.345678    0.000000
     0.000000    0.000000   12.345678
    

    .

    $ awk -f tst.awk numbers file1 file2 file3
    

    .

    $ ls
    file1  file1.new  file2  file2.new  file3  file3.new  numbers  tst.awk
    

    .

    $ tail -n +1 file*.new
    ==> file1.new <==
    87.654321    0.000000    0.000000
     0.000000   87.654321    0.000000
     0.000000    0.000000   87.654321
    
    ==> file2.new <==
    18.765432    0.000000    0.000000
     0.000000   18.765432    0.000000
     0.000000    0.000000   18.765432
    
    ==> file3.new <==
    21.876543    0.000000    0.000000
     0.000000   21.876543    0.000000
     0.000000    0.000000   21.876543
    

    如果您安装GNU awk,那么您可以使用-i inplace进行“inplace”编辑,而不是创建新的输出文件,如果这对您有用的话。

    匿名用户

    按照@Zelnes的想法,这里有一个版本,它只是根据您的file2数据生成一个新文件:

    #!/bin/bash
    
    while read value ; do
        ((fileNum++))
        awk -v input="$value" '
          END{
            for (i=1;i<4;i++) {
              for (j=1;j<4;j++) {
                #dbg print "#dbg: i=" i "\tj=" j;
                if (j==i) {
                  #dbg print "#dbg: matched"
                  arr[i]=input
                } else {
                  #dbg print "#dbg: setting arr["j"]="arr[j]
                  arr[j]=0.0
                }
              }
              printf("%0.6f\t%0.6f\t%0.6f\n",arr[1],arr[2],arr[3])}} ' /dev/null \
           > file"$fileNum".txt
    done < newValues.txt
    

    可以更改printf以获得格式问题所需的确切行间距。将末尾的newValue. txt更改为实际输入文件的名称。您甚至可以将其设为/path/to/一些地方/else/newValue.txt

    你会需要的

    chmod +x myDataGenerator 
    

    在运行它之前。

    cd到您要在其中创建文件的目录,然后使用其完整路径调用脚本,即

    /full/path/to/myDataGenerator
    

    如果您想要尽可能小的程序,请删除#dbg行。

    如果您想了解脚本的工作原理,请一次取消注释一行#dbg,了解正在做什么,然后取消注释下一个#dbg

    IHTH