質問をすることでしか得られない、回答やアドバイスがある。

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

新規登録して質問してみよう
ただいま回答率
85.48%
AWK

AWKは、UNIX 上で開発されたプログラミング言語で、CSVファイルなどのテキストファイルの処理を目的にデザインされています。

Q&A

解決済

1回答

7120閲覧

awkの複数デリミタ指定について

neeg

総合スコア68

AWK

AWKは、UNIX 上で開発されたプログラミング言語で、CSVファイルなどのテキストファイルの処理を目的にデザインされています。

0グッド

0クリップ

投稿2017/08/13 10:36

編集2017/08/13 10:44

現在、awkのデリミタの指定と、フィールドのカウント方法について悩んでいます。

現在、デジカメの画像ファイルのファイル名を、通番から撮影した日に変更するコマンドをawkで作成しています。(環境はcygwinです)
具体的には以下のようなlsの出力を利用して、

% ls --full-time -rwxrwx---+ 1 user None 814420 2017-08-12 14:31:16.000000000 +0900 CIMG1954.JPG -rwxrwx---+ 1 user None 1021175 2017-08-13 17:02:14.000000000 +0900 CIMG1955.JPG -rwxrwx---+ 1 user None 1010903 2017-08-12 14:31:40.000000000 +0900 CIMG1956.JPG -rwxrwx---+ 1 user None 924994 2017-08-12 14:31:46.000000000 +0900 CIMG1957.JPG -rwxrwx---+ 1 user None 1088210 2017-08-12 14:32:48.000000000 +0900 CIMG1958.JPG -rwxrwx---+ 1 user None 1358633 2017-08-12 14:32:54.000000000 +0900 CIMG1959.JPG

以下のようなフォーマットに変換して、スクリプトを生成する出力を得ようとしています。

mv CIMG1991.JPG "2017-08-12 14:44:48.JPG" mv CIMG1992.JPG "2017-08-12 14:44:56.JPG" mv CIMG1994.JPG "2017-08-12 14:45:16.JPG" mv CIMG1995.JPG "2017-08-12 14:46:14.JPG" mv CIMG1996.JPG "2017-08-12 14:46:34.JPG" mv CIMG1997.JPG "2017-08-12 14:49:28.JPG"

そのためのコマンドが以下の通りです。
デリミタには-Fオプションを使って、空白文字とピリオドの2つを指定しています。

% ls --full-time | awk -F "[. ]" '{ print "mv " $10 "." $11 " \"" $6 " " $7 "." $11 "\"" ;}'

ですが、実際に上記のコマンドを実行すると、ファイルサイズによって出力がまちまちになって困っています。
具体的には、ファイルサイズが1MB以下のファイルでフィールドの順番が狂うようで、以下のような出力になります。

-rwxrwx---+ 1 user None 1021175 2017-08-13 17:02:14.000000000 +0900 CIMG1955.JPG -rwxrwx---+ 1 user None 1010903 2017-08-12 14:31:40.000000000 +0900 CIMG1956.JPG -rwxrwx---+ 1 user None 924994 2017-08-12 14:31:46.000000000 +0900 CIMG1957.JPG ↓ ↑デリミタ(スペース)が2つある ↓ mv CIMG1955.JPG "2017-08-13 17:02:14.JPG" mv CIMG1956.JPG "2017-08-12 14:31:40.JPG" mv +0900.CIMG1957 "924994 2017-08-12.CIMG1957" ←期待していない出力になる

ポイントになるのは、最後のファイルが1MB以下のため、グループとサイズの間に、スペースが2つあることだと推測しています。(他のファイルも全て同じ症状です)

ただ、私の知っている範囲では、awkの仕様ではデリミタが複数続いても、それ全体を1つのデリミタとしてカウントするように思っています。
具体的には以下の通りです。

% echo a b | awk -F' ' '{print $2;}' ←aとbの間には2つのスペースがあるが、、、 b ←bは2番目のフィールドとして認識されている

推測ですが、awkはデリミタが単数の場合と、複数の場合では、フィールドのカウント方法が変わる仕様のような気がしています。
(いろいろと調べましたが、確定的な答えは得られませんでした)

なんとか期待通りの出力を得ようとして半分適当にいろいろと試してみたのですが、当初の目的をいまだに果たせずにいます。
どのようなコマンドを書いたらよろしいでしょうか。
awkのバージョンは以下の通りです。

% awk -V GNU Awk 4.1.4, API: 1.1 (GNU MPFR 3.1.5, GNU MP 6.1.2) Copyright (C) 1989, 1991-2016 Free Software Foundation.

ご助言いただければ幸いです。よろしくお願いいたします。

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

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

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

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

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

guest

回答1

0

ベストアンサー

下のようにすればよいでしょう。

echo a b | awk -F'[ .]*' '{print $2;}'

man awk にはこうあります。

Otherwise, FS is expected to be a full regular expression. In the special case that FS is a single space, fields are separated by runs of spaces and/or tabs and/or newlines.

つまり、基本的にFSは正規表現として扱われるが、例外的に、シングルスペースが指定されているとき(デフォルトはこれ)、フィールドはスペースやタグや改行の連続したもの(runs of...)で区切られる。

投稿2017/08/13 11:38

KojiDoi

総合スコア13671

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

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

neeg

2017/08/13 12:58

できましたできました! ありがとうございます。 manの方は私も見ていたのですが、スペースの場合には連続した物で区切られる、なずなのになんで区切られないんだろう? というのが疑問だったのです。 ですが、あまり追求しても仕方ないかな、、、(消極的) いずれにせよ、できました。ありがとうございました。
KojiDoi

2017/08/13 13:44

ですから、「連続したスペース全部」で「一つのスペーサー」ということですね。実際問題として便利な仕様と言えるでしょう。それではまずいときは、-F '[ ]'とか設定してあげればいいわけです。
neeg

2017/08/18 01:00

私の質問は ・「連続したスペース全部」で「一つのスペーサー」になるはず ・なのに、なぜならないのか? ですがそこは認識合ってますか?
KojiDoi

2017/08/18 03:40

正規表現を指定した場合は「シングルスペースが指定されているとき」に該当しないので、「一つのスペーサーになる」例外規定は適用されないということですよ。
neeg

2017/08/18 08:09

あ、なるほど。 ・セパレータがシングルスペースの時 ではなく ・FSがシングルスペースの時 に例外が発動するということですね。 そういうことであればやっと理解できました。 # そもそも、デフォルトが例外っていうところがややこしいですね。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問