最初の列の内容をループ構造に置き換えます。

最初の列の内容をループ構造に置き換えます。

変更したい最初の列を持つファイルがあります。たとえば、次のファイルがあります(元のファイルには複数の列がありましたが、次の列は2列に切り捨てられ、ファイルの末尾に空白行がある可能性があります)。 )。

テスト.txt:

0 a
2 b  
3 c 
4 d
5 e


最初の列の内容を0 - > 2、2 - > 3、3 - > 5、4 - > 0、5 - > 4に変更する必要があります。最終ファイルは次のとおりです。

2 a
3 b
5 c
0 d
4 e


私は次のようにawkを使ってみました。

awk '$1=="0"{$1="2"} $1=="2"{$1="3"} $1=="3"{$1="5"} $1=="4"{$1="0"} $1=="5"{$1="4"};1' test.txt

しかし、awkは1行ずつ読み取らず、必要なものを変更しないので、出力は次のようになります。

4 a
4 b
4 c
0 d
4 e


私が必要なPython、sed、awk、または他のスクリプトツールに変換するのに役立つ人は誰でも歓迎します。

答え1

AWKは実際に1行ずつ読みます。next各割り当て後に印刷後にステートメントを追加すると、残りのコードはスキップされます。

awk '$1=="0"{ $1="2"; print; next }
     $1=="2"{ $1="3"; print; next }
     $1=="3"{ $1="5"; print; next }
     $1=="4"{ $1="0"; print; next }
     $1=="5"{ $1="4"; print; next }1' infile

または、代わりに制御フラグを使用してください。

awk '!s && $1=="0"{ $1="2"; s=1 }
     !s && $1=="2"{ $1="3"; s=1 }
     !s && $1=="3"{ $1="5"; s=1 }
     !s && $1=="4"{ $1="0"; s=1 }
     !s && $1=="5"{ $1="4"; s=1 }
                  { print; s=0  }' infile

ただし、次のようにすべての操作を実行できます。

awk -F'( )' 'BEGIN{ split("2 1 3 5 0 4", map) }
$1!=""{ $1=($1+1 in map)?map[$1+1]:$1 }1' infile

そして分割(文字列、arryName)関数map以下のようにインデックスと値の名前付き配列を作成し、配列はFSに基づいて分割されます(デフォルトはSpace / Tabs)。

Index        Value
map[<0>+1] -->   2
map[<1>+1] -->   we choice it 1 so it will be unchanged for <1> --> 1
map[<2>+1] -->   3
map[<3>+1] -->   5
map[<4>+1] -->   0
map[<5>+1] -->   4

<#>角度内の数字は最初の列の値であり、awkでは、配列のインデックス付けはゼロではなく1から始まり、列の値を1ずつ増やし、マップされた配列からその値を取得します。


一般的な解決策として(ただし、ほとんどのカスタムキー/値は連続的であり、配列インデックスをキーとして使用できるため、上記のソリューションを引き続き使用します)、そうでない場合は、次のことができます。

awk -F'( )' 'BEGIN{ len=split("0 2 2 3 3 5 4 0 5 4", map) }
{ for(i=1; i<=len/2; i+=2 ) if($1==map[i]){ $1=map[i+1]; break} }1' infile

答え2

$ awk 'BEGIN{split("1 3 5 0 4",map); map[0]=2} {$1=map[$1]} 1' file
2 a
3 b
5 c
0 d
4 e



答え3

シェルを含む:

while read -r idx rest; do
  case $idx in 
    0) idx=2 ;; 
    2) idx=3 ;; 
    3) idx=5 ;; 
    4) idx=0 ;; 
    5) idx=4 ;;
  esac 
  echo "$idx $rest"
done < test.txt

出力を元のファイルに書き換えるには、次のいずれかを実行します。

tmp=$(mktemp)
while ... < test.txt > "$tmp" && mv "$tmp" test.txt

またはmoreutilsインストール

while ... < test.txt | sponge test.txt

またはパール:

perl -pe '
    BEGIN {%map = (0=>2, 2=>3, 3=>5, 4=>0, 5=>4)}
    s{(\d+)}{$map{$1} // $1}e
' test.txt

答え4

GNU sedを使用して拡張正規表現モードを有効にします-E。最初の列を分離し、シナリオに従ってパターン空間を調整するy///コマンドを実行することから始めますtransliterate(現在は最初の列のみがあります)。次に、元の行を呼び出して2番目の列を取得し、元の最初の列を削除します。

sed -e '
  /^\S\s/!b
  s//&\n/;h
  s/\n.*//
  y/02345/23504/
  G;s/\n.*\n//
' file

2 a
3 b
5 c
0 d
4 e

他の方法は次のとおりです。

perl -lpe '
  s/^\S\s/
      $& =~ tr[02345]
              {23504}r
  /ex;
' file

またはライナーとして:

perl -lpe 's|^\S\s|$& =~ tr/02345/23504/r|e' file
python3 -c 'import sys
ifile = sys.argv[1]
with open(ifile) as fh:
  for l in fh:
    l = l.strip()
    p = l.find(" ")
    if p == 1:
      f1,rest = l[:p],l[p:];print(f1.translate(f1.maketrans("02345","23504")),rest,sep="")
    else:print(l)
' file

awk -v u="02345" -v v="23504" '
  BEGIN {
    gsub(/./, "&" FS, u)
    gsub(/./, "&" FS, v)
    split(u, a)
    for (i=1; i<=split(v,b); i++)
      c[a[i]] = b[i]
  }
  $1 in c{$1=c[$1]}1
' file

関連情報