awkコマンドを用いた前処理の紹介

awk command 1/N

公開日: 2021-12-16
更新日: 2023-09-28

  Table of Contents

awkってなに?

  • テキストデータをいろいろ加工したり処理したりする際(=前処理)に活躍するシェルコマンド
  • ワンライナーで活躍してくれます

Dependencyと設定

今回は gawk ベースで紹介します. gawkが入っていない場合は以下のラインでインストール:

1
% sudo apt install gawk

インストールすると awk コマンドは gawk を参照しているはずです. その確認方法は、

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 % sudo update-alternatives --display awk
awk - auto mode
  link best version is /usr/bin/gawk
  link currently points to /usr/bin/gawk
  link awk is /usr/bin/awk
  slave awk.1.gz is /usr/share/man/man1/awk.1.gz
  slave nawk is /usr/bin/nawk
  slave nawk.1.gz is /usr/share/man/man1/nawk.1.gz
/usr/bin/gawk - priority 10
  slave awk.1.gz: /usr/share/man/man1/gawk.1.gz
  slave nawk: /usr/bin/gawk
  slave nawk.1.gz: /usr/share/man/man1/gawk.1.gz
/usr/bin/mawk - priority 5
  slave awk.1.gz: /usr/share/man/man1/mawk.1.gz
  slave nawk: /usr/bin/mawk
  slave nawk.1.gz: /usr/share/man/man1/mawk.1.gz

awkコマンド

  • 簡単な行ベースのテキストファイルを処理するコマンド
  • 演算機能もあり、プログラミング言語としても使用されています
  • イメージとしては grep にプログラム機能をつけたコマンド

Syntax

1
% awk [option] [command] [file path]

Option一覧

短いオプション 長いオプション 意味
-f program-file --file program-file awk への第 1 引数を用いるかわりに、
AWK プログラムをファイル program-file から読み込む
-F fs --field-separator fs 入力フィールドセパレータ (変数 FS の値)をfsする
field seperatorのdefaultはwhite space
-v var=val --assign var=val プログラムを実行する前に、変数 var に値 val を設定

awkで使用できる主な組み込み変数

変数名 意味
ARGC 引数の個数
ARGV 引数(配列)
ENVIRON 環境変数を収めた連想配列。例えば環境変数LANGならばENVIRON[“LANG”]と参照できる
FILENAME 現在処理しているファイルの名前
FNR 現在処理しているファイルのレコード番号
FS フィールドの区切り文字(-Fオプションで変更可能、デフォルトはスペース)
NR 現在処理しているレコード番号(行番号)
OFS 出力時のフィールドの区切り(デフォルトは空白)
ORS 出力時のレコードの区切り(デフォルトは改行)
RS レコードの区切り(デフォルトは改行)

awkコマンドを体験する

(1) 1~5までのsequenceのうち偶数のみを抽出する

1
2
3
% seq 5 | awk '/[24]/'
2
4

awk /正規表現/grep 正規表現と同じ挙動になります. 別の書き方として2で割り切れる数値が偶数であること利用して次のような書き方も可能です.

1
2
3
% seq 5 | awk '$1%2==0'
2
4

awkコマンドにシングルクォートで囲まれた箇所の中の$1は読み込んだ行の一列目を意味します. awkコマンドはzshやbashといったシェルで定義された関数以外にawkの中で定義された関数を呼び出して前処理を実行します.

そのため、「awk独自の関数に基づいた命令です」ということを明示する必要がありますが、 これが理由でawkコマンドにシングルクォートで囲った範囲が出てくると考えてください.

(2) 1~5までのsequenceのうち偶数のみを抽出する & 抽出結果に「偶数」という文字列を付与する

解答

1
2
3
% seq 5 | awk '$1%2==0{printf("%s, 偶数\n", $1)}'
2, 偶数
4, 偶数

別解

1
% seq 5 | awk '$1%2==0{print($1, "偶数")}'

今回は、抽出結果に「偶数」という文字列を付与して出力したいので、何かしらの形で「偶数」という文字列をprintfに与える必要があります. 出力したい文字列はダブルクォートで囲むことで実現できます. シングルクォートだとawkコマンド適応領域という意味とコンフリクトしてしまうので、「ダブルクォート」と理解すると覚えやすいです.

はじめに、偶奇判定のgrep(前提条件コマンド)を実行してから、{}で囲まれたawkコマンドを実行しています.

(3) 1~5までのsequenceのうち、数値に応じて奇数偶数という文字列を付与する

解答

1
2
3
4
5
6
% seq 5 | awk '$1%2==0{print($1, "偶数")}$1%2{print($1, "奇数")}'
1 奇数
2 偶数
3 奇数
4 偶数
5 奇数

別解

1
2
3
4
5
6
% seq 5 | awk '{a = ""; $1%2 ? a = "奇数" :a = "偶数"; print($1, a)}'
1 奇数
2 偶数
3 奇数
4 偶数
5 奇数

「別解」では、CONDITION ? 真の場合に返す値 : 偽の場合に返す値という三項演算子を用いて記述しています. awkコマンドのフロートしては、

  1. 変数aを空文字で定義
  2. 三項演算子を用いてaをアップデート
  3. 読み込んだテキストの一列目とその値に応じたaをターミナルに出力

という3つのコマンドを実行しています. この3つのコマンドの接続方法は、セミコロン;でコマンドをつなぐことで可能となります.

(4) 1~5までのsequenceのうち、数値に応じて奇数偶数という文字列を付与する

1
% seq 5 | awk 'BEGIN{a=0}$1%2==0{print($1, "偶数")}$1%2{print($1, "奇数")}{a+=$1}END{print("合計", a)}'
  • BEGIN, ENDは、それぞれ「awkが1行目の処理を始める前」「awkが最終行の処理を終えた後」という状況にマッチします.
  • 上記は、最初に変数 a を0に初期化して、行の処理のたびに+1のincrementを実施し、最後にその時のaの状態を出力するという処理です.

(5) awkコマンドを用いてディスクの空き領域を表示する

解答

1
2
3
% df -m | awk 'NR==1 {print "1G-Blocks", "GB-"$4}; NR>=2 {x+=$2/(2**10); y+=$4/(2**10)}; END {print x, y}'
1G-Blocks GB-Available
541.072 458.293
  • 「df」を実行すると、ディスクの空き領域が表示されます
  • -m optionは指定したサイズの倍数で表示するオプション(MB単位)

別解

1
% df -h --total  

(6) CSVファイルの各フィールドを文字列結合して複数ディレクトリを作成する

1
2
3
4
5
6
7
%ls
test.csv
% cat test.csv
store_name,store_code
a,100
b,101
c,101

上記のようにtest.csvの2つのfieldにstore_name,store_codeがカレントワーキングディレクトリに格納されているとします. この2つのfieldを組合せて、<store_name>_<store_code>というdirectoryをカレントワーキングディレクトリ以下に作成したいとします. この場合のshell scriptは以下.

1
2
3
% awk -F "," 'NR>1{print $1"_"$2}' test.csv| awk '{system("mkdir "$1)}'
% ls
a_100/  b_101/  c_101/  test.csv

解説

awk -F "," 'NR>1{print $1"_"$2}' test.csvawk '{system("mkdir "$1)}'の2つのパートに分けて考えます. 前者はCSVファイルをカンマセパレートで各カラムをREADし、それらを文字列結合し出力しています. その後、その出力結果を後者に渡してsystem()でLinuxコマンドをawkの中で呼び、 mkdirでディレクトリを作成しています.

awkコマンドを用いたデータ整形

このセクションで用いるデータ

ID,stand_name,user_name,power,speed,range,duration,agility,growth
001,スタープラチナ,空条承太郎,A,A,C,A,A,A
002,マジシャンズレッド,モハメド・アヴドゥル,B,B,C,B,C,D
003,ハーミットパープル,ジョセフ・ジョースター,D,C,D,A,D,E
004,ハイエロファントグリーン,花京院典明,C,B,A,B,C,D
005,タワー・オブ・グレー,グレーフライ,E,A,A,C,E,E
006,シルバーチャリオッツ,J・P・ポルナレフ,C,A,C,B,B,C
007,ダークブルームーン,キャプテン・テニール,C,C,C,B,C,D
008,力・ストレングス,フォーエバー,B,D,D,A,E,E
009,エボニーデビル,呪いのデーボ,D,D,A,B,D,B
010,イエローテンパランス,ラバーソール,D,C,E,A,E,D
011,ハングドマン,J・ガイル,C,A,A,B,D,D
012,エンペラー,ホル・ホース,B,B,B,C,E,E
013,エンプレス,ネーナ,C,E,A,A,D,D
014,ホウィール・オブ・フォーチュン,ズィー・ズィー,B,D,D,A,E,D
015,ジャスティス,エンヤ婆,D,E,A,A,E,E
016,ラバーズ,鋼入りのダン,E,D,A,A,D,E
017,サン,アラビア・ファッツ,B,E,A,A,E,E
018,デス・サーティーン,マニッシュ・ボーイ,C,C,E,B,D,B
019,ジャッジメント,カメオ,B,B,C,B,D,D
020,ハイプリエステス,ミドラー,C,B,A,A,D,D
021,ザ・フール,イギー,B,C,D,C,D,C
022,ゲブ神,ンドゥール,C,B,A,B,D,D
023,トト神,ボインゴ,E,E,E,A,E,E
024,クヌム神,オインゴ,E,E,E,A,E,E
025,アヌビス神,キャラバン・サライ,B,B,E,A,E,C
026,バステト女神,マライア,E,E,B,A,E,E
027,セト神,アレッシー,D,D,E,C,D,D
028,オシリス神,ダニエル・J・ダービー,E,D,D,C,D,D
029,ホルス神,ペット・ショップ,B,B,D,C,E,C
030,アトゥム神,テレンス・T・ダービー,D,C,D,B,D,D
031,ティナー・サックス,ケニー・G,E,E,D,A,E,E
032,クリーム,ヴァニラ・アイス,B,B,D,C,C,D
033,ザ・ワールド,DIO,A,A,C,A,B,B

awkの組み込み変数

変数 説明
NR the current number of the input records
NF the number of fields of the current record
FS The input field separator
defaultはwhite space
FSで区切り文字を設定できる
RS The input record separator
defaultは改行
OFS The output field separator
print出力時のfieldの区切り文字を指定
ORS The output record separator
print出力時のrecordの区切り文字
FPAT The input field pattern
どのようなパターンをフィールドとして認識するかを定義することができる

例題 (1) 各レコードのfieldの数を出力する

1
2
3
4
5
6
% awk -F "," '{print NF, $0}' example.csv | head -n 5
9 ID,stand_name,user_name,power,speed,range,duration,agility,growth
9 001,スタープラチナ,空条承太郎,A,A,C,A,A,A
9 002,マジシャンズレッド,モハメド・アヴドゥル,B,B,C,B,C,D
9 003,ハーミットパープル,ジョセフ・ジョースター,D,C,D,A,D,E
9 004,ハイエロファントグリーン,花京院典明,C,B,A,B,C,D

例題 (2) ファイルの行数を出力する

1
2
% awk 'END {print NR}' example.csv
34

or, シンプルにwcコマンドを用いて改行数をカウントして

1
2
% cat example.csv | wc -l
33

指定した行を出力する

先頭5行を表示したい場合

任意の先頭の行数を出力したい場合は、一般的にはheadコマンドを用います.

1
2
3
4
5
6
% head -n 5 example.csv
ID,stand_name,user_name,power,speed,range,duration,agility,growth
001,スタープラチナ,空条承太郎,A,A,C,A,A,A
002,マジシャンズレッド,モハメド・アヴドゥル,B,B,C,B,C,D
003,ハーミットパープル,ジョセフ・ジョースター,D,C,D,A,D,E
004,ハイエロファントグリーン,花京院典明,C,B,A,B,C,D

awkコマンドを用いて表示する場合は

1
% awk 'NR<=5 {print}' example.csv

6行目から10行目を表示したい場合

1
2
3
4
5
6
% awk 'NR<=10 && NR>=6 {print}' example.csv
005,タワー・オブ・グレー,グレーフライ,E,A,A,C,E,E
006,シルバーチャリオッツ,J・P・ポルナレフ,C,A,C,B,B,C
007,ダークブルームーン,キャプテン・テニール,C,C,C,B,C,D
008,力・ストレングス,フォーエバー,B,D,D,A,E,E
009,エボニーデビル,呪いのデーボ,D,D,A,B,D,B

headerを含めたい場合は

1
2
3
4
5
6
7
% awk '(NR<=10 && NR>=6)||(NR==1) {print}' example.csv
ID,stand_name,user_name,power,speed,range,duration,agility,growth
005,タワー・オブ・グレー,グレーフライ,E,A,A,C,E,E
006,シルバーチャリオッツ,J・P・ポルナレフ,C,A,C,B,B,C
007,ダークブルームーン,キャプテン・テニール,C,C,C,B,C,D
008,力・ストレングス,フォーエバー,B,D,D,A,E,E
009,エボニーデビル,呪いのデーボ,D,D,A,B,D,B

RowのFilter

承太郎を含む行を抽出する場合

1
2
% awk '/承太郎/ {print}' example.csv
001,スタープラチナ,空条承太郎,A,A,C,A,A,A

headerを含めたい場合は、

1
2
3
% awk '/承太郎/||(NR==1) {print}' example.csv
ID,stand_name,user_name,power,speed,range,duration,agility,growth
001,スタープラチナ,空条承太郎,A,A,C,A,A,A

承太郎 or Dioを含む行を抽出する場合

1
2
3
% awk '/承太郎|DIO/ {print}' example.csv
001,スタープラチナ,空条承太郎,A,A,C,A,A,A
033,ザ・ワールド,DIO,A,A,C,A,B,B

Jという文字列を含む行のうちポルという文字列があとに続く行を抽出

Jという文字列を含む行は3つあります

1
2
3
4
% awk '/J/ {print}' example.csv 
006,シルバーチャリオッツ,J・P・ポルナレフ,C,A,C,B,B,C
011,ハングドマン,J・ガイル,C,A,A,B,D,D
028,オシリス神,ダニエル・J・ダービー,E,D,D,C,D,D

このうち、「ポル」という文字列が後に出現する行を抽出したい場合は

1
2
% awk '/J.*ポル/ {print}' example.csv 
006,シルバーチャリオッツ,J・P・ポルナレフ,C,A,C,B,B,C

または、

1
2
% awk '/J.{1,}ポル/ {print}' example.csv
006,シルバーチャリオッツ,J・P・ポルナレフ,C,A,C,B,B,C

「神」という文字を含む行を除外して出力したい場合

スターダストクルセイダースは「オシリス神」など「神」を名前に含むスタンドが数体出現します. それらを除くスタンダ一覧を表示したいとします

1
% awk '!/神/ {print}' example.csv

Columnのフィルター

特定のカラムのみコンソールに出力したい場合

  • シンボル$と数字の組合せを用いることで特定のカラムを指定することができます
  • field seperatorのdefaultはwhite spaceなので、csv fileを対象に操作するときは FS = ","の指定をします
  • スタンドと使用者の組をここでは抽出したいとします

解答

1
% awk -F ',' '{print $2, $3}' example.csv

別解

1
% awk '{print $2, $3}' FS=',' example.csv

or

1
% awk 'BEGIN{FS=","} {print $2, $3}' example.csv

カラム別に条件をつけて行を抽出する

  • power, speed fieldがAのスタンドのみを抽出したいとします
  • header行も出力したいとします
1
2
3
4
% awk -F ',' 'NR==1 || ($4=="A" && $5 == "A") {print $2, $3}' example.csv
stand_name user_name
スタープラチナ 空条承太郎
ザ・ワールド DIO

IDが5以下の行のみを抽出したい場合は

1
2
3
4
5
% awk -F"," '$1<5{print $0}' example.csv
001,スタープラチナ,空条承太郎,A,A,C,A,A,A
002,マジシャンズレッド,モハメド・アヴドゥル,B,B,C,B,C,D
003,ハーミットパープル,ジョセフ・ジョースター,D,C,D,A,D,E
004,ハイエロファントグリーン,花京院典明,C,B,A,B,C,D

スタンド使用者の名前がアルファベットを含む行のみ抽出する

1
2
3
4
5
6
7
8
% awk -F"," 'NR==1 || $3~/[A-Za-z]/{print $0}' example.csv
ID,stand_name,user_name,power,speed,range,duration,agility,growth
006,シルバーチャリオッツ,J・P・ポルナレフ,C,A,C,B,B,C
011,ハングドマン,J・ガイル,C,A,A,B,D,D
028,オシリス神,ダニエル・J・ダービー,E,D,D,C,D,D
030,アトゥム神,テレンス・T・ダービー,D,C,D,B,D,D
031,ティナー・サックス,ケニー・G,E,E,D,A,E,E
033,ザ・ワールド,DIO,A,A,C,A,B,B

もし「スタンド使用者の名前がアルファベットを含まない行のみ抽出」したい場合は

1
% awk -F"," 'NR==1 || $3!~/[A-Za-z]/{print $0}' example.csv

Delimiterを変更して出力したい場合

  • csvファイルをtsvとして出力します

解答

1
2
3
4
5
6
7
% awk 'BEGIN{FS=",";OFS="\t"} {for(i=1;i<=NF-1;i++) printf $i" "; print ""}' example.csv > example.tsv
% head -n 5 example.tsv 
ID stand_name user_name power speed range duration agility 
001 スタープラチナ 空条承太郎 A A C A A 
002 マジシャンズレッド モハメド・アヴドゥル B B C B C 
003 ハーミットパープル ジョセフ・ジョースター D C D A D 
004 ハイエロファントグリーン 花京院典明 C B A B C 

別解: gsub

1
% awk 'gsub(",","\t")' example.csv
  • gsub functionはglobal substitutionの略

別解: sed version

1
% sed 's/,/\t/g' example.csv > example.tsv
  • この時、-i optionはつけないこと

複数のcsv fileを結合したい場合

  • example_2.csvという以下のファイルを準備します. このファイルとexample.csvのファイルを結合し、新たなmerged_with_header.csvを作りたいとします.

Data

ID,stand_name,user_name,power,speed,range,duration,agility,growth
034,クレイジー・ダイヤモンド,東方仗助,A,A,D,B,B,C
035,アクア・ネックレス,片桐安十朗,C,C,A,A,C,E
036,ザ・ハンド,虹村億泰,B,B,D,C,C,C
037,バッド・カンパニー,虹村形兆,B,B,C,B,C,C
038,レッド・ホット・チリ・ペッパー,音石明,A,A,A,A,C,A
039,錠前,小林玉美,E,E,A,A,E,E
040,エコーズACT1,広瀬康一,E,E,B,B,C,A
041,サーフィス,間田敏和,B,B,C,B,C,C
042,ラブ・デラックス,山岸由花子,B,B,C,A,E,B
043,エコーズACT2,広瀬康一,C,D,B,B,C,A
044,パール・ジャム,トニオ・トラサルディー,E,C,B,A,E,C
045,アクトン・ベイビー,静・ジョースター,E,E,なし,A,E,A
046,ヘブンズ・ドアー,岸辺露伴,D,B,B,B,C,A
047,ラット,虫喰い&虫喰いでない,B,C,D,B,E,C
048,ハーヴェスト,矢安宮重清,E,B,A,A,E,C
049,キラークイーン,吉良吉影,A,B,D,B,B,A
050,シンデレラ,辻彩,D,C,C,C,A,C
051,シアーハートアタック,吉良吉影,A,C,A,A,E,A
052,エコーズACT3,広瀬康一,B,B,C,B,C,A
053,アトム・ハート・ファーザー,吉良吉廣,E,E,なし,A,E,E
054,ボーイ・Ⅱ・マン,大柳賢,C,B,C,A,C,C
055,アース・ウインド・アンド・ファイヤー,支倉未起隆,C,C,なし,A,C,C
056,ハイウェイ・スター,墳上裕也,C,B,A,A,E,C
057,ストレイ・キャット,猫草,B,E,なし,A,E,C
058,スーパー・フライ,鋼田一豊大,E,E,なし,A,E,E
059,エニグマ,宮本輝之輔,E,E,C,A,C,C
060,チープ・トリック,乙雅三,E,E,E,A,E,E
061,キラークイーン・バイツァ・ダスト,吉良吉影,B,B,A,A,D,A

解答

1
% awk '(NR == 1) || (FNR > 1)' *.csv > merged_with_header.csv
  • 必ずしもIDはsortされていないことに注意
  • NR == 1 は最初に読み込んだファイルの先頭行という意味
  • FNRは処理しているファイルの行を意味します

もし,headerを除去してmergedしたい場合は

1
% awk '(FNR > 1)' *.csv > merged_without_header.csv

IDでsortした形で結合したい場合

csvsort

  • この手法はIDの表現が変わってしまうので非推奨
1
2
3
4
5
6
7
% csvsort merged_with_header.csv > sorted_merged.csv
% head -n 5 sorted_merged.csv
ID,stand_name,user_name,power,speed,range,duration,agility,growth
1,スタープラチナ,空条承太郎,A,A,C,A,A,A
2,マジシャンズレッド,モハメド・アヴドゥル,B,B,C,B,C,D
3,ハーミットパープル,ジョセフ・ジョースター,D,C,D,A,D,E
4,ハイエロファントグリーン,花京院典明,C,B,A,B,C,D

headとtailの組合せでsort (推奨)

1
% head -n1 merged_with_header.csv && tail -n+2 merged_with_header.csv | sort > sorted_merged_2.csv

なお、csvsortで作成したファイルとの差分の行数を確認すると

1
2
% diff -u sorted_merged.csv sorted_merged_2.csv | awk 'NR>3  && /+/{print NR}' | wc -l
61

特定のフィールドの部分文字列を抽出したい場合:substr()

特定のフィールドの部分文字列を抽出したいとします.

1
% echo "2021/09/01 09:00:00 UTC,10,200,3000"

上記の文字列から日付部分のみ, 2021/09/01を抽出したい場合、substr()関数を用いることで 文字列の頭n文字目からm文字を抜き出して表示することができます.

1
2
% echo "2021/09/01 09:00:00 UTC,10,200,3000"|awk -F, 'BEGIN{OFS=","}{print substr($1, 1, 10),$2,$3,$4}'
2021/09/01,10,200,3000

末尾から文字を抜き出したい場合

123456789, abcdefghijklmnというレコードが与えられた時、カンマセパレートでそれぞれのフィールドから後ろから数えて5文字を抽出したいとします. substr(field, start, length)のうちlengthを省略すると、startから文末までを抽出してくれる機能を利用します.

1
2
% echo "123456789, abcdefghijklmn"|awk -F, '{print substr($1, length($1)-4), substr($2, length($2)-4)}'
56789 jklmn

FPATを用いたフィールド内にカンマへの対応

CSVファイルには「フィールド内にカンマを含む場合にはフィールドをダブルクォートで括る」というルールがあります. 文字列内に,が含まれるケースや、売上金額などの数値データで初期設定の関係で3桁カンマ区切りのデータが含まれるCSVファイルを扱うとき、単純に awk -F","と指定してしまうと、自分では想定していない形でフィールドが定義される可能性があります.

例:文字列内にカンマを含むケース

1
2
% echo '"¥10,000",¥100,"¥99,000"' |awk -F"," '{print $2}'
000"

¥100が期待される出力結果ですが、"¥10,000"000"が出力されてしまいます.

組込変数FPATの導入

いままではフィールドセパレーターを定義してawkコマンドを用いていましたが、 フィールド内にカンマが含まれる場合はフィールドのパターンを定義することで対応することができます. 例として、

1
2
% echo '"¥10,000",¥100,"¥99,000"' |awk -v FPAT='([^,]+)|(\"[^\"]+\")' '{print $2}'     
¥100

上記の例では([^,]+)|(\"[^\"]+\")という正規表現をFPATに指定することで「カンマを含まない、またはダブルクォートで囲まれていて、その中にダブルクォートを含まない文字列」というフィールドパターンを定義しています.

正規表現 意味
[^...] 角括弧に含まれる文字以外にマッチ
+ 直前の文字が 1回以上 繰り返す場合にマッチ
最長一致, 条件に合う最長の部分に一致
| OR条件

REMARKS

  • FPATを渡す場合は、-F のセパレーター指定してはいけない
  • 二重クォートでエスケープされたレコードはFPAT='([^,]+)|(\"[^\"]+\")'で対応することができません

Markdownファイルの編集に役に立つawkコマンドの紹介

順序付きリストの整形

問題

Markdownでは、行頭が数字とドットとspaceではじまる行は順序付きリストと呼ばれ、何かのリストを各項目別に番号を振って列挙する際によく使用されます. いま以下のように, item.mdが与えられたとします:

1
2
3
4
5
6
7
8
9
10
11
# AAA

1. fasukdhals
1. jhdlasjhdkla
1. 1jakl;dj;asld;l1.17638

# BBB

7. 86789132789
9. slikrujdhklsjfkljsljf
10. ksfhdljksdhfhsdlj

これは順番通りになっていないので、行の位置は変えずに、行頭の数字を振り直し、item_fixed.mdを作成したいとします. つまり、item_fixed.mdの中身は

1
2
3
4
5
6
7
8
9
10
11
# AAA

1. fasukdhals
2. jhdlasjhdkla
3. 1jakl;dj;asld;l1.17638

# BBB

1. 86789132789
2. slikrujdhklsjfkljsljf
3. ksfhdljksdhfhsdlj

解答

1
% cat item.md|awk '/^[0-9]+\.\s/{a++;$1=a".";print}/^#/{a=0}!/^[0-9]+\./' > item_fixed.md

解説

  • awk '/正規表現/'grep 正規表現と同じ挙動
  • '/^[0-9]+\.\s/, /^#/, !/^[0-9]+\./'の3つのルールを指定
    • '/^[0-9]+\./: 行頭が数字, ドット, spaceで始まる行を抽出
    • /^#/: 行頭がシャープから始まる行を抽出
    • !/^[0-9]+\./': 行頭が数字, ドット, spaceで始まらない行を抽出
  • /^#/{a=0}: 見出しマークを目印にaの値をリセット

References



Share Buttons
Share on:

Feature Tags
Leave a Comment
(注意:GitHub Accountが必要となります)