.txtファイルを使用してfileAのテキスト名を変更しようとしていますsed
。 2番目の列はfileA
製品名の完全な説明です。商品名を商品IDに変更したいです。ただし、説明の一部のテキストには同様の内容があります(例fileA
:)。 「オレンジジュース」は2行と4行に2回現れます。
renamefile
製品名をsed
。sed
ファイルA:
AB12345 100 0 Apple juice 20/05 AB
CD67890 150 0 Orange juice with pulp 22/05 CS
EF25879 100 0 Watermelon juice 19/05 CG
GH96314 98 0 Orange juice 20/05 PU
IJ74123 95 0 Strawberry juice with lemon 17/05 ST
ファイルの名前を変更します。
s/\<Apple juice\>/3071/g
s/\<Orange juice with pulp\>/3072/g
s/\<Orange juice\>/3073/g
s/\<Watermelon juice\>/3074/g
s/\<Apple juice with lemon\>/3075/g
s/\<Strawberry juice with lemon\>/3076/g
現在の出力:
AB12345 100 0 3071 20/05 AB
CD67890 150 0 **3073** 22/05 CS
EF25879 100 0 3074 19/05 CG
GH96314 98 0 3073 20/05 PU
IJ74123 95 0 3076 17/05 ST
希望の出力:
AB12345 100 0 3071 20/05 AB
CD67890 150 0 3072 22/05 CS
EF25879 100 0 3074 19/05 CG
GH96314 98 0 3073 20/05 PU
IJ74123 95 0 3076 17/05 ST
私は正確に一致する場合にのみ交換に役立つことをどこかで見つけたので、「<>」を使用しています。しかし、この場合はうまくいかないようです。 (エラーは現在の出力で太字で表示されます。)
文字列の置き換えでは、最初の2つの文字列が一致した後に、より多くの単語を考慮し、その名前をそのIDに置き換えるより良い効率的な方法がありますか?
十分明確ではない場合は教えてください。ありがとうございます!
答え1
renamefile
長さに基づいて並べ替え、長い名前を最初に置き換える必要があります。
awk '{ print length, $0 }' renamefile| sort -nr | cut -d" " -f2- > renamefile2
出力
s/\<Strawberry juice with lemon\>/3076/g
s/\<Orange juice with pulp\>/3072/g
s/\<Apple juice with lemon\>/3075/g
s/\<Watermelon juice\>/3074/g
s/\<Orange juice\>/3073/g
s/\<Apple juice\>/3071/g
それでは問題なく申請できます。
sed -f renamefile2 fileA
説明する:
awk
ループ行
length
awk に組み込まれた関数です。引数なしで呼び出すと、現在の行のサイズが印刷されます(詳細は奇妙な長さ)$0
現在の行
次のコマンドは、行自体の横にある各行の長さを印刷します。
awk '{ print length, $0 }' renamefile
24 s/\<Apple juice\>/3071/g
35 s/\<Orange juice with pulp\>/3072/g
25 s/\<Orange juice\>/3073/g
sort
入力したテキストが並べ替えられます。
-n
数字で並べ替えられます-r
結果が下向きになるように反転します。
cut
テキストの一部を選択します(最終スクリプトでは長さを必要とせず、行の一部をsed
選択するだけです)。
-d" "
ここに区切り文字を指定しますspace
。-f2-
フィールド2から行末まで
答え2
/
製品名の後に常に2桁の数字、1桁の数字、2桁の数字が続く場合は、正規表現で囲み、逆参照を使用してそれ自体に置き換えることができます。
前の 4 つの空白文字を一致させてその文字に置き換えることもできます。
ファイルの名前を変更します。
s/( {4})Apple juice( [[:digit:]]{2}\/[[:digit:]]{2})/\13071\2/
s/( {4})Orange juice with pulp( [[:digit:]]{2}\/[[:digit:]]{2})/\13072\2/
s/( {4})Orange juice( [[:digit:]]{2}\/[[:digit:]]{2})/\13073\2/
s/( {4})Watermelon juice( [[:digit:]]{2}\/[[:digit:]]{2})/\13074\2/
s/( {4})Apple juice with lemon( [[:digit:]]{2}\/[[:digit:]]{2})/\13075\2/
s/( {4})Strawberry juice with lemon( [[:digit:]]{2}\/[[:digit:]]{2})/\13076\2/
出力:
$ sed -Ef renamefile fileA
AB12345 100 0 3071 20/05 AB
CD67890 150 0 3072 22/05 CS
EF25879 100 0 3074 19/05 CG
GH96314 98 0 3073 20/05 PU
IJ74123 95 0 3076 17/05 ST
答え3
awkを使用する方が簡単です。
$ cat tst.awk
BEGIN {
id = 3071
map["Apple juice"] = id++
map["Orange juice with pulp"] = id++
map["Orange juice"] = id++
map["Watermelon juice"] = id++
map["Apple juice with lemon"] = id++
map["Strawberry juice with lemon"] = id++
}
match($0,/^((\S+\s+){3})(.*\S)((\s+\S+){2})/,a) {
$0 = a[1] map[a[3]] a[4]
print
}
$ awk -f tst.awk file
AB12345 100 0 3071 20/05 AB
CD67890 150 0 3072 22/05 CS
EF25879 100 0 3074 19/05 CG
GH96314 98 0 3073 20/05 PU
IJ74123 95 0 3076 17/05 ST
\<
上記はGNU sedと\>
単語の境界を使用しているため、GNU awkを使用しています。
答え4
GNU sedを使用して最初に名前変更ファイルを動的に変更し(手動で編集する必要がないことを意味します)、それをsedコードとしてファイルAで編集します。
名前が変更されたファイルで変更したのは、\>の代わりにRHS境界で改行を見つけることでした。しかし、その前にfileAのパターン空間に改行文字を挿入します。
$ sed -re '
1i\
s/(\\s+\\S+){2}\\s*$/\\n&/
s/\\>/\\n/
' renamefile | sed -rf - fileA
出力:
AB12345 100 0 3071 20/05 AB
CD67890 150 0 3072 22/05 CS
EF25879 100 0 3074 19/05 CG
GH96314 98 0 3073 20/05 PU
IJ74123 95 0 3076 17/05 ST