変更したい最初の列を持つファイルがあります。たとえば、次のファイルがあります(元のファイルには複数の列がありましたが、次の列は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