Awk交换来自不同列的值

时间:2017-12-22 11:36:14

标签: arrays bash awk

我有一个以下结构的文件:

4 1:4 3:1 6:1 56:2 57:4 58:7 59:1 66:2
1 2:1 56:1 57:1 58:2 59:2 65:1
8 1:2 2:1 3:8 12:1 56:1 57:2 58:2 59:2 66:1 67:2

我需要做的是将与56和57相关的值切换为与58和59相关的值:

4 1:4 3:1 6:1 56:7 57:1 58:2 59:4 66:2
1 2:1 56:2 57:2 58:1 59:1 65:1
8 1:2 2:1 3:8 12:1 56:2 57:2 58:1 59:2 66:1 67:2

目前我正尝试使用以下内容执行至少两列的替换:

awk '{
         for ( i=2;i<=NF;i++ )
         {
            split(, a, ":") 
            arr[a[1]] = a[2]
         }
      }
      END {
         n = asorti(arr, dest)
         ORS= 
         for ( i=1; i<=n; i++ ) 
         { 
            if ( dest[i] != 56 && dest[i] != 58 ) 
               print dest[i] ":" arr[dest[i]]
            else 
            { 
               if ( dest[i] == 56 ) 
                  print dest[i] ":" arr[dest[i+2]] 
               if ( dest[i] == 58 ) 
                  print dest[i] ":" arr[dest[i-2]]
            }
         }
      }' file

然而,这看起来很笨重,最终索引没有正确排序。 将欣赏任何其他解决方案。

2 个答案:

答案 0 :(得分:1)

如果您可以依赖订购总是56,57,58,59,那么您可以使用sed执行此操作:

     <?php 

      $images = glob("slike/*.*");

      sort($images);

      foreach ($images as $img) {

        echo '<div class="image_wrapper"><img src="'.$img.'"></div>';

      }

    ?>

抓住所有部件并在更换中重新洗牌。

奇数编号的捕获组指的是&#34;标签&#34;以及任何主要内容,第一种情况除外,我们不必触及该部分线路。偶数的是指数值。

答案 1 :(得分:1)

GNU awk 解决方案:

awk '{ 
         r=gensub(/\<(56:)([0-9]+) (57:)([0-9]+) (58:)([0-9]+) (59:)([0-9]+)/, 
                 "\\1\\6 \\3\\8 \\5\\2 \\7\\4", "g"); 
         print r 
     }' file

输出:

4 1:4 3:1 6:1 56:7 57:1 58:2 59:4 66:2
1 2:1 56:2 57:2 58:1 59:1 65:1
8 1:2 2:1 3:8 12:1 56:2 57:2 58:1 59:2 66:1 67:2
  

<强> gensub(regexp, replacement, how [, target])

     

在目标字符串target中搜索常规字符串   表达regexp。如果how是以“g”或“G”开头的字符串   (“ global ”的缩写),然后将regexp的所有匹配替换为   replacement