シェルスクリプトからid作成
改行を含むレコードがある場合は正しく動かないので
訂正します。
csvはパーサーがないと編集することが難しいので、
シェルスクリプトからpythonを使います。
下の例はpython3
(python2だとprintするときにバイト列になっているかもしれない。)
上の例の場合は
csvのヘッダー付きで出力します。
(使う場合は、変数
idc,delimiterをシェルから
引数を渡せるようにするなどして
外から変更できるように書いてください。)
理解につまずきそうなのは
cin = csv.reader(sys.stdin,delimiter=delimiter)
の部分だろうか。
なぜ、ファイルの指定のはずなのに、
sys.stdinと標準入力をここで渡すことができるのか
わからない人がいるかもしれないが、
厳密に言うと
標準出力もファイルなのでこのようなことができる。
上流に|(パイプ)があるので、
これにより、
下流のpythonで標準入力から、
catで読み込んだ内容を受け取れるというわけである。
これはpython自体の仕様でなく、
コンピュータ自体の仕様
なので、
pythonだろうが、rubyだろうがC言語だろうが
同じようなことができる。
もちろんOSが変わっても同様なことができる
(Windowsのcmdにはパイプはないが、bashのパイプのように
標準入力を渡すという機能があるものがあれば、やはり正しく動く。)
これでとりあえず、pythonのcsvが正しく
パースしている限り、すべての形式のcsvに対して
正しく動く
pythonのこの処理をbashの関数内で呼ぶことも考えたが、
python,ruby,perl等
スクリプト言語に
そのような仕事をさせることは向かないので、
コンパイル言語であるGo言語で後日書く。
!!訂正
ここ以下の文章はcsvに改行を含まないレコードの場合のみ
動くので注意!!(改行を含まないレコードの場合はこれでよい。)
csvファイルなどに
id列を追加したい場合は、
nlコマンドを使う。
下の例はすべて、
6桁まで対応できるが、
idが100万以上必要な場合は
nl -w7
以上にすること。
カラム名がないcsvファイルの場合
$ nl -n 'rz' -s ',' csvファイル名 | sed 's/^0*//'
nlはファイルを行番号付きで表示させるコマンド。nl -nのrzは行番号を右詰めで表示して、長さが足りない場合は左側を0で表示させる。
最後に先頭の0を消去することで、idを表示させている。
カラム名つきのcsvファイルの場合
$ cat csvファイル名 | sed '1s/^/#id,/' | nl -n 'rz' -s ',' -bp^[^¥(#id,¥)] | sed '1s/^ *,#id/id/' | sed 's/^0*//'
解説すると
#id,から始まる行が他にもあったら、正しく動かないが、まずないはず。
これを関数にまとめると↓のようになる。
function pasteid() {
if [ -z $1 ]; then
return 0
fi
local filename=$1
if test ! '-c' = $2 || [ -z $2 ]; then
nl -n 'rz' -s ',' $filename | sed 's/^0*//'
else
cat $filename | sed '1s/^/#id,/' | nl -n 'rz' -s ',' -bp^[^¥(#id,¥)] | sed '1s/^ *,#id/id/' | sed 's/^0*//'
fi
}
これでファイルにidをつけたものが表示される。
$ pasteid ファイル名 -c(cはオプションつけなくてもよい。)
ファイルにid列を上書きする場合は下のように行う必要がある。
$ tempfile=$(mktemp)
$ trap 'rm ${tempfile}' EXIT
$ pasteid ファイル名 -c | cat > $tempfile
$ mv $tempfile ファイル名
一時ファイルの作成、trapで削除については、下のサイトを参考にさせていただきました。
https://hydrocul.github.io/wiki/commands/mktemp.html
訂正します。
csvはパーサーがないと編集することが難しいので、
シェルスクリプトからpythonを使います。
下の例はpython3
(python2だとprintするときにバイト列になっているかもしれない。)
cat staff.csv | python -c '
import csv
import sys
#idcolumnがいる場合はtrueにする。
idc = True
#外側からデリミタを指定できるようにする。
delimiter = ","
cin = csv.reader(sys.stdin,delimiter=delimiter)
i = 0 if idc else 1
for row in cin:
if i == 0:
row = ["id"] + row
else:
row = [str(i)] + row
print(delimiter.join(row))
i += 1
' | cat >> 指定のファイル等
上の例の場合は
csvのヘッダー付きで出力します。
(使う場合は、変数
idc,delimiterをシェルから
引数を渡せるようにするなどして
外から変更できるように書いてください。)
理解につまずきそうなのは
cin = csv.reader(sys.stdin,delimiter=delimiter)
の部分だろうか。
なぜ、ファイルの指定のはずなのに、
sys.stdinと標準入力をここで渡すことができるのか
わからない人がいるかもしれないが、
厳密に言うと
標準出力もファイルなのでこのようなことができる。
上流に|(パイプ)があるので、
これにより、
下流のpythonで標準入力から、
catで読み込んだ内容を受け取れるというわけである。
これはpython自体の仕様でなく、
コンピュータ自体の仕様
なので、
pythonだろうが、rubyだろうがC言語だろうが
同じようなことができる。
もちろんOSが変わっても同様なことができる
(Windowsのcmdにはパイプはないが、bashのパイプのように
標準入力を渡すという機能があるものがあれば、やはり正しく動く。)
これでとりあえず、pythonのcsvが正しく
パースしている限り、すべての形式のcsvに対して
正しく動く
pythonのこの処理をbashの関数内で呼ぶことも考えたが、
python,ruby,perl等
スクリプト言語に
そのような仕事をさせることは向かないので、
コンパイル言語であるGo言語で後日書く。
!!訂正
ここ以下の文章はcsvに改行を含まないレコードの場合のみ
動くので注意!!(改行を含まないレコードの場合はこれでよい。)
csvファイルなどに
id列を追加したい場合は、
nlコマンドを使う。
下の例はすべて、
6桁まで対応できるが、
idが100万以上必要な場合は
nl -w7
以上にすること。
カラム名がないcsvファイルの場合
$ nl -n 'rz' -s ',' csvファイル名 | sed 's/^0*//'
nlはファイルを行番号付きで表示させるコマンド。nl -nのrzは行番号を右詰めで表示して、長さが足りない場合は左側を0で表示させる。
最後に先頭の0を消去することで、idを表示させている。
カラム名つきのcsvファイルの場合
$ cat csvファイル名 | sed '1s/^/#id,/' | nl -n 'rz' -s ',' -bp^[^¥(#id,¥)] | sed '1s/^ *,#id/id/' | sed 's/^0*//'
解説すると
- 最初にカラム名が付いている一行目だけ、#id,とid用のカラム名を足している。#とつけたのは、後でnlで行番号を追加するときにこの行だけ、採番を行わないようにするため。
- nl -bpは採番を行う行を正規表現を用いて選択するオプション。nl -bp^[^¥(#id,¥)]で先頭が#id,となっている行だけ除いて採番を行うようにしている。
- 最後に (半角スペース何個か)#id,となっている部分をとって、上と同様に左詰めの0を削除している。
#id,から始まる行が他にもあったら、正しく動かないが、まずないはず。
これを関数にまとめると↓のようになる。
function pasteid() {
if [ -z $1 ]; then
return 0
fi
local filename=$1
if test ! '-c' = $2 || [ -z $2 ]; then
nl -n 'rz' -s ',' $filename | sed 's/^0*//'
else
cat $filename | sed '1s/^/#id,/' | nl -n 'rz' -s ',' -bp^[^¥(#id,¥)] | sed '1s/^ *,#id/id/' | sed 's/^0*//'
fi
}
これでファイルにidをつけたものが表示される。
$ pasteid ファイル名 -c(cはオプションつけなくてもよい。)
ファイルにid列を上書きする場合は下のように行う必要がある。
$ tempfile=$(mktemp)
$ trap 'rm ${tempfile}' EXIT
$ pasteid ファイル名 -c | cat > $tempfile
$ mv $tempfile ファイル名
一時ファイルの作成、trapで削除については、下のサイトを参考にさせていただきました。
https://hydrocul.github.io/wiki/commands/mktemp.html
コメント
コメントを投稿