現在、次のような内容のテキストファイルが複数あります(多くの行があります)。
565 0 10 12 23 18 17 25
564 1 7 12 13 16 18 40 29 15
各行を次の形式に変更したい:
0 565:10:1 565:12:1 565:23:1 565:18:1 565:17:1 565:25:1
1 564:7:1 564:12:1 564:13:1 564:16:1 564:18:1 564:40:1 564:29:1 564:15:1
Sedを使用して上記を行う方法はありますか?または、Pythonに頼る必要がありますか?
はい、sedでできますが、他のツールの方が簡単です。例えば:
$ awk '{
printf "%s ", $2;
for(i=3;i<=NF;i++){
printf "%s:%s:1 ",$1,$(i)
}
print ""
}' file
0 565:10:1 565:12:1 565:23:1 565:18:1 565:17:1 565:25:1
1 564:7:1 564:12:1 564:13:1 564:16:1 564:18:1 564:40:1 564:29:1 564:15:1
awkは入力の各行を空白で分割し(デフォルト)、各フィールドを$1
、$2
、$N
として保存します。そう:
printf "%s ", $2;
は、2番目のフィールドと末尾のスペースを出力します。for(i=3;i<=NF;i++){ printf "%s:%s:1 ",$1,$(i) }
:フィールド3から最後のフィールド(NF
はフィールドの数)を反復処理し、それぞれについて、最初のフィールド、:
、次に現在のフィールドを出力しますおよび:1
。print ""
:これは最後の改行を出力するだけです。またはPerl:
$ Perl -ane 'print "$F[1] "; print "$F[0]:$_:1 " for @F[2..$#F]; print "\n"' file
0 565:10:1 565:12:1 565:23:1 565:18:1 565:17:1 565:25:1
1 564:7:1 564:12:1 564:13:1 564:16:1 564:18:1 564:40:1 564:29:1 564:15:1
-a
は、Perl
をawk
のように動作させ、その入力を空白で分割します。ここでは、フィールドは配列@F
に格納されます。つまり、最初のフィールドは$F[0]
、2番目の$F[1]
などになります。
print "$F[1] "
:2番目のフィールドを出力します。print "$F[0]:$_:1 " for @F[2..$#F];
:フィールド3から最後のフィールドまで繰り返します($#F
は配列@F
の要素数です。したがって、@F[2..$#F]
は3番目の要素から始まる配列スライスを取得します。配列の最後)、1番目のフィールド、:
、次に現在のフィールド、:1
を出力します。print "\n"
:これは最後の改行を出力するだけです。がここにあります 恐ろしい sed
方法!
$ sed -r 's/^([0-9]+) ([0-9]+) ([0-9]+)/\2 \1:\3:1/; :a s/([0-9]+)(:[0-9]+:1) ([0-9]+)( |$)/\1\2 \1:\3:1 /; t a; s/ $//' file
0 565:10:1 565:12:1 565:23:1 565:18:1 565:17:1 565:25:1
1 564:7:1 564:12:1 564:13:1 564:16:1 564:18:1 564:40:1 564:29:1 564:15:1
より読みやすい:
sed -r '
s/^([0-9]+) ([0-9]+) ([0-9]+)/\2 \1:\3:1/
:a
s/([0-9]+)(:[0-9]+:1) ([0-9]+)( |$)/\1\2 \1:\3:1 /
t a
s/ $//'
-r
EREを使用s/old/new/
old
をnew
に置き換えます^([0-9]+)
行の先頭にいくつかの数値を保存します\1
最初に保存されたパターンへの後方参照:a
スクリプトのこのセクションにラベルを付けるa
( |$)
スペースまたは行末t
最後の置換が成功したかどうかをテストします。成功した場合は、次のコマンドを実行しますa
ラベル:a
を見つけて、もう一度実行しますs/ $//
末尾のスペースを削除そのため、最初の部分に構造を追加した後、構造の最後のインスタンスを繰り返し見つけて、次の番号に適用します...
しかし、私は他のツールがそれを簡単にすることに同意します...
Awkの場合:
awk '{printf "%s ",$2; for (i=3; i<=NF; i++) printf $1":"$i":1 "; printf "\n"}' file
またはbashを使用:
while read -r -a a; do # read line to array a
printf "%s " ${a[1]} # print column #1
for ((i=2;i<${#a[@]};i++)); do # loop from column #2 to number of columns
printf "%s " "${a[0]}:${a[$i]}:1" # print content/values
done
echo # print line break
done < file # read file from stdin
出力:
0 565:10:1 565:12:1 565:23:1 565:18:1 565:17:1 565:25:1 1 564:7:1 564:12 :1 564:13:1 564:16:1 564:18:1 564:40:1 564:29:1 564:15:1
まあ、あなたはsedでそれを行うことができますが、pythonも動作します。
$ ./reformatfile.py input.txt
0 565:10:1 565:12:1 565:23:1 565:18:1 565:17:1 565:25:1
1 564:7:1 564:12:1 564:13:1 564:16:1 564:18:1 564:40:1 564:29:1 564:15:1
reformatfile.py
の内容は次のとおりです。
#!/usr/bin/env python3
import sys
with open(sys.argv[1]) as fd:
for line in fd:
words = line.strip().split()
pref = words[0]
print(words[1],end=" ")
new_words = [ ":".join([pref,i,"1"]) for i in words[2:] ]
print(" ".join(new_words))
これはどのように作動しますか?特に特別なことは何もありません。最初のコマンドライン引数を読み取り用のファイルとして開き、各行を「単語」または個々のアイテムに分解します。最初の単語はpref
変数になり、2番目の標準出力(words [1])にスペースで終わる項目を出力します。次に、リスト内包表記と、pref、各Word、および文字列"1"
の一時リストでの.join()
関数を使用して、新しい「単語」のセットを作成します。最後のステップはそれらを印刷することです
awk
の場合:
awk '{printf("%s ", $2); for(i=3; i<NF; i++) printf("%s:%s:1 ", $1, $i);\
printf("%s:%s:1\n", $1, $NF)}' file.txt
スペースで区切られたフィールドを目的の形式にフォーマットすることがすべてです。
printf("%s ", $2)
は、2番目のフィールドに末尾スペースを出力します
for(i=3; i<NF; i++) printf("%s:%s:1 ", $1, $i)
は、最後から3番目から2番目のフィールドを繰り返し、目的の形式(最初のフィールド、次にコロン、次に現在のフィールド、次にコロン、最後に1)でフィールドを出力します。
printf("%s:%s:1\n", $1, $NF)
は最後のフィールドを改行付きで出力します
例:
% cat file.txt
565 0 10 12 23 18 17 25
564 1 7 12 13 16 18 40 29 15
% awk '{printf("%s ", $2); for(i=3; i<NF; i++) printf("%s:%s:1 ", $1, $i); printf("%s:%s:1\n", $1, $NF)}' file.txt
0 565:10:1 565:12:1 565:23:1 565:18:1 565:17:1 565:25:1
1 564:7:1 564:12:1 564:13:1 564:16:1 564:18:1 564:40:1 564:29:1 564:15:1