🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
bash

bash(Bourne-again-Shell)は sh(Bourne Shell)のインプリメンテーションに様々な機能が追加されたシェルです。LinuxやMac OS XではBashはデフォルトで導入されています。

CSV

CSV(Comma-Separated Values)はコンマで区切られた明白なテキスト値のリストです。もしくは、そのフォーマットでひとつ以上のリストを含むファイルを指します。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

zsh

zshは、UNIX系OSのシェルの1つです。 cshやksn系のコマンドライン編集機能も実装されたシェルです。

データベーススペシャリスト

データベーススペシャリスト試験 (DB)は、IPA 独立行政法人 情報処理推進機構の実施している国家資格です。

Q&A

解決済

5回答

2409閲覧

linuxコマンドで各列の重複単語を削除したい

TaroNoguchi

総合スコア18

bash

bash(Bourne-again-Shell)は sh(Bourne Shell)のインプリメンテーションに様々な機能が追加されたシェルです。LinuxやMac OS XではBashはデフォルトで導入されています。

CSV

CSV(Comma-Separated Values)はコンマで区切られた明白なテキスト値のリストです。もしくは、そのフォーマットでひとつ以上のリストを含むファイルを指します。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

zsh

zshは、UNIX系OSのシェルの1つです。 cshやksn系のコマンドライン編集機能も実装されたシェルです。

データベーススペシャリスト

データベーススペシャリスト試験 (DB)は、IPA 独立行政法人 情報処理推進機構の実施している国家資格です。

0グッド

0クリップ

投稿2019/11/21 08:21

編集2019/11/22 04:55

Linuxコマンドでcsvファイルの各列を洗って重複する単語があれば片方を削除したいです。
考えているのは各行ループの中で、cut -d ,等でカンマを区切り文字として重複単語を見つけ、削除したいです。
具体的には以下のような感じです。

kingyo,panda,pig,pig neko,inu,sakana,penguin sea,see,sea,mountain taro,taro,taro1,taro2 kanji,hiragana,katakana,eigo,kanji

kingyo,panda,pig neko,inu,sakana,penguin sea,see,mountain taro,taro1,taro2 kanji,hiragana,katakana,eigo

のように変換したいです。

何か解決策はございますでしょうか?

【以降追記】

解凍していただいた皆様、ありがとうございます。

追加で各単語の行末についている数字を削除する必要が出てきたので以下のようにdatamash transposeを用いてループの中で一行ずつやりました。
$1に元のファイル、$2に書き出し先のファイル名を指定しています。

shell

1while read row; do 2 echo $row | 3 4 sed -e 's/,/\t/g' | # , =>tab 5 datamash transpose | # transpose 6 7 # 行末についている1〜2桁の数字を削除 8 sed -e "s/[0-9]*$//" | 9 sed -e "s/[0-9][0-9]*$//" | 10 11 sort -u | # 重複行削除 12 tr '\n' ',' | # 改行をカンマにして一列へ戻す 13 sed "s/^,//g" >> $2 # 行頭のカンマ削除 14done < $1

こちらのやり方で何かよくない点等ありましたらご意見いただけるとありがたいです。

P.S. このデータは元データの5カラム目以降をcutして作業しています。作業後元のファイルに結合する必要がありますが、pasteコマンドで結合したところ数カ所で一つのセルに複数の行・列が格納されてしまいました。なので元のデータを切り取って作業するのではなく元のデータのままでsedコマンドなどを「〜列目以降のモノに対してだけ」使いたいと思ってます。これに関して何か良い方法はありますか?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答5

0

take88さんの回答と発想は同じですが、

  • 作業用ハッシュをmy指定しておかないと同じ単語が別の行に再登場したときに問題が発生する。
  • -F,aオプションを使うとさらにシンプルにワンライナーが書ける。

というわけで、

perl -F, -anle 'my %x; print join(",", grep {!$x{$_}++} @F)' file.csv

質問の追加に伴う追記

単に各項の数字を削除したいだけなのにわざわざ行列の入れ替えを行なうとは、あまりに無駄すぎると思います。
sedを使うなら、s/[0-9]*,/,/g; s/[0-9]*$//;で済みます。

追加事項に対応してみたスクリプト。さすがにワンライナーは辛くなってきたのでスクリプトファイルにしてみます。

$ cat coluniq.pl while(<>){ chomp; my %d; my @F=split(/,/, $_); my($from, $to) = (4, $#F); foreach my $x (@F[$from..$to]){ $x=~s/[0-9]+$//; $d{$x}=0; } print join(",", @F[0..($from-1)], keys %d); } $ cat in.csv 1,1,1,1,kingyo,panda,pig,pig 1,1,1,1,neko,inu,sakana,penguin 1,1,1,1,sea,see,sea,mountain 1,1,1,1,taro,taro,taro1,taro2 $ perl ~/work/coluniq.pl in.csv 1,1,1,1,panda,kingyo,pig 1,1,1,1,inu,penguin,sakana,neko 1,1,1,1,see,mountain,sea

投稿2019/11/21 12:16

編集2019/11/22 14:43
KojiDoi

総合スコア13692

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

perlを使い少し趣向を変えて、正規表現だけでやってみました。

bash

1$ perl -ple 's/(,?)([^,]+)(?{$`!~$2?$1.$2:""})/$^R/g' file.csv

投稿2019/11/22 01:51

amanoese

総合スコア132

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

otn

2019/11/22 07:22

Perl 5.10だと正規表現のエラーで、Perl 5.30だと kingyo,panda,pig,pig neko,inu,sakana,penguin sea,see,mountain taro,taro1,taro2 kanji,hiragana,katakana,eigo,kanji が出ました。pig が残る。
amanoese

2019/11/25 05:06

調べてみましたがperl 5.14以上で動作する正規表現のようですね。 改めてdocker上で5.10~5.30の安定版で試してみましたが5.14以降ではすべて正しく動作するようです。 5.30では正しく動作します。
otn

2019/11/25 12:19

失礼しました。上記は、WindowsのMSYSでやっていたのですが、file.csvの改行コードがCRLFでした。 LFにすると大丈夫です。行末の語だけおかしいので、気付くべきでした。 Perl最新版を使おうとWindowsでやったのが失敗のもと。
guest

0

awkで書こうとするとちょっと長くなりそうだったのでやめて、sedで。

sh

1cat <<EOF | 2kingyo,panda,pig,pig 3neko,inu,sakana,penguin 4sea,see,sea,mountain,sea 5taro,taro,taro1,taro2 6kanji,hiragana,katakana,eigo,kanji 7EOF 8sed -r ':x;s/(^|,)([^,]+)(.*),\2(,|$)/\1\2\3\4/g;t x'

同じ単語が3つ以上あるかもしれないので、同じ単語が無くなるまでt でループします。

投稿2019/11/21 13:15

編集2019/11/21 13:17
otn

総合スコア85882

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

Perlのワンライナーでやってみました。

shell

1$ cat file.csv 2kingyo,panda,pig,pig 3neko,inu,sakana,penguin 4sea,see,sea,mountain 5taro,taro,taro1,taro2 6kanji,hiragana,katakana,eigo,kanji 7 8$ perl -nle 'print join ",", grep {!$buf{$_}++} split ",",$_;' file.csv 9kingyo,panda,pig 10neko,inu,sakana,penguin 11sea,see,mountain 12taro,taro1,taro2 13kanji,hiragana,katakana,eigo 14

投稿2019/11/21 11:25

編集2019/11/21 11:32
take88

総合スコア1467

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

自己解決

while read row; do echo "Executing commands in $count th row ..." echo "..." echo "..." count=$(( count + 1)) echo $row | cut -d, -f 5- | # 5列目以降を nkf -X --overwrite | # 半角カナを全角カナに sed -e 's/,/\t/g' | # , =>tab datamash transpose | # transpose sort -u | # 重複行削除 tr '\n' ',' | # 改行をカンマにして一列へ戻す sed 's/^"//g' | # 行頭のクオーテーション削除 sed "s/^,//g" >> $2 # 行頭のカンマ削除 echo >> $2 done < $1

投稿2019/11/26 06:46

TaroNoguchi

総合スコア18

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問