
次のデータを含むファイルがあります。
a 1
b 2
c,d,e 3,4,5
f 6
g,h 7,8
...次のような出力が必要です。
a 1
b 2
c 3
d 4
e 5
f 6
g 7
h 8
Pythonを使用してこれを行うことはできますが、シェルスクリプトを使用してこれを試したいと思います。まず、区切り文字「、」を含む行を分割してから作業を続行します。これまで私はこれを行を分離するために使用しました。
perl -F, -ane 'print if $#F >=1' filename
...しかし、次のステップで詰まっています。
答え1
そしてperl
$ perl -lane '@v=split/,/,$F[1]; $i=0;
print "$_ $v[$i++]" for split/,/,$F[0]' ip.txt
a 1
b 2
c 3
d 4
e 5
f 6
g 7
h 8
最初/2番目の列を分割し、インデックスカウンタを初期化してから、別の列を繰り返し分割してペアを印刷します。
-a
オプションは自動的に入力行をスペースに分割し、結果を@F
配列に保存します。
答え2
Awk
回避策(最初のフィールドに含まれる「キー」の数は$1
常に2番目のフィールドに含まれる「値」の数と一致すると仮定します$2
):
awk '$1 ~ /,/{
len = split($1, keys, ",");
split($2, vals, ",");
for (i = 1; i <= len; i++) print keys[i], vals[i];
next
}1' file
出力:
a 1
b 2
c 3
d 4
e 5
f 6
g 7
h 8
答え3
sedエディタを使用してこれを行う1つの方法は次のとおりです。
sed -e '
s/,/\n/
s/\(\n.*[[:blank:]]\)\([^,]*\),/ \2\1/
P;D
' input.file
布材:
- 2番目のフィールドで、カンマで区切られた先行要素を切り捨てます。
- その後、この要素は最初のフィールドのコンマ区切りの前の要素に追加されます。
- 最初のフィールドの前の要素を印刷してから削除します。
- パターンスペースの残りの部分が空になるまでこのプロセスを繰り返します。
Perlを使用する別の方法は次のとおりです。
perl -lane '
my($kref, $vref, %h) = map { [split /,/] } @F[0,1];
@h{@$kref} = @$vref;
print "$_ $h{$_}" for @$kref;
' input.file
別の方法は次のとおりです。
perl -lpe 'print "$1 $3" while s/^([^,]*),(.*\h)([^,]*),/$2/' input.file
布材:
- 次の正規表現を見てください。 (Perlはファイルから一度に1行ずつ読みます)。
- ^([^,]*)現在行の最初のフィールドにあるコンマで区切られた先行要素を選択する必要があります。これは$ 1変数に保存されます。
- (.*\時間)whileループの次の反復では、最初のフィールドの2番目のコンマで区切られた要素から始めて、2番目のフィールドの2番目のコンマで区切られた要素の先頭までの内容を保持する必要があります。これは$ 2変数に保存されます。
- ([^,]*)カンマで区切られた先行要素は、現在の行の2番目のフィールドから選択する必要があります。これは$ 3変数に保存されます。
- これで "$1 $3" が STDOUT に印刷され、その行は $2 に縮小されます。 whileループは、この編集された行の前の行の$ 2だけ操作を再実行します。 ..... これは s/// が成功するまで繰り返されます。コンマが足りないと失敗します。この時点で、「c 5」行の残りの部分は、-pモードでPerlのデフォルト動作を介してSTDOUTに印刷されます。
- 最初と2番目のフィールドで、カンマで区切られた先行要素を取得します。
- これらの要素を印刷して削除して、現在のレコードを縮小します。
- 現在のレコードに2つのカンマがある場合は、レコードを繰り返します。
- 最後のペアは、Perlの-pオプションのために自動的に印刷されます。
perl -lane '
my($kref, $vref) = map { [split /,/] } @F;
print shift @$kref, " ", shift @$vref while @$kref && @$vref;
' input.file
布材:
- キーは@$kref配列に格納され、その値は@$vrefに格納されます。ここにはハッシュは関係ありません。
- また、配列の上部を印刷してから上部を削除してフラッシュし、両方の配列が空でない場合は繰り返します。
出力:
a 1
b 2
c 3
d 4
e 5
f 6
g 7
h 8
答え4
「シェルスクリプトの使用」 - これはbashです:
while read -r key value; do
IFS=, read -ra keys <<<"$key"
IFS=, read -ra vals <<<"$value"
for ((i=0; i < ${#keys[@]}; i++)); do
echo "${keys[i]} ${vals[i]}"
done
done <<END
a 1
b 2
c,d,e 3,4,5
f 6
g,h 7,8
END