dorapon2000’s diary

忘備録的な。セキュリティとかネットワークすきです。

macの「ディスクがほとんど一杯です」通知を消す方法 (消せない)

macの「ディスクがほとんど一杯です」通知は消しても数分するとまた表示されて本当に邪魔です。こっちは少ない容量を一生懸命やりくりしているんだと突っ込みたくなります。通知を消す方法をグーグル先生に聞いても、ディスクの整頓術ばっかりで肝心の通知を切る方法がありません。

英語で調べたら数年の悩みが一瞬で片付いたので共有します。

f:id:dorapon2000:20181216121307p:plain


環境

通知を消す方法

apple.stackexchange.com

$ launchctl unload -w /System/Library/LaunchAgents/com.apple.diskspaced.plist

ターミナル上でこれ打つだけです。こんなことに悩まされていたとは、、、

デフォルトだと20GBより容量が少なくなったときに通知が出るみたいで、その数を変えることもできます。

$ defaults write com.apple.diskspaced minFreeSpace 1

自分はこっちの方法で1GBにしました。再起動すれば反映されます


追記

www.reddit.com

The minFreeSpace option and many others appear to have been removed recently, for no reason.

MojaveだとminFreeSpaceというオプションが使えなくなったようでした。

通知を表示させなくする方も試したのですが、これも上で言及されているエラーが出てしまいました。

$ launchctl unload -w /System/Library/LaunchAgents/com.apple.diskspaced.plist
/System/Library/LaunchAgents/com.apple.diskspaced.plist: Operation not permitted while System Integrity Protection is engaged

他のサイトの方法でも通知消えず。

apple.stackexchange.com

$ defaults write com.apple.diskspaced removeAllNotifications -bool true
$ killall diskspaced

tutel.me

$ defaults write com.apple.diskspaced freeSpaceWarningLevel 1
$ defaults write com.apple.diskspaced warningInterval 36000000
$ launchctl stop com.apple.diskspaced && launchctl start com.apple.diskspaced

# 設定した値がロードできてません
$ grep -A6 debugLog <(strings $(find /System/Library/PrivateFrameworks -name diskspaced -print -quit))
debugLog (BOOL) - log additional debug information. Default: NO
Commands:
removeAllNotifications - Removes all scheduled and delivered user notificiations.
removeAllNotifications
com.apple.diskspaced
_mbsetupuser
Ignoring low disk notification during migration.
--
debugLog
systemUpdateDate
com.apple.updatesettings
Interval since system update :%f
alloc
init
lowSpaceTimer

これらもMojaveのときに消えてしまったんでしょうか汗

$ grep com.apple.diskspaced /var/log/system.log
Dec 16 15:32:08 dorapon-MBA com.apple.xpc.launchd[1] (com.apple.xpc.launchd.domain.user.501): Service "com.apple.xpc.launchd.unmanaged.diskspaced.2257" tried to register for endpoint "com.apple.diskspaced" already registered by owner: com.apple.diskspaced

ログにはすでに登録されている旨が書かれてますね。

只今模索中


追記2

検索しても皆さん解決策がなくて困ってるようですね汗。今後改善して、設定で消せるようになることを期待します。

参考

BoostNoteからMarkdownを抽出する

タイトルのとおりです。 最近Typoraというマークダウンエディタを発見しまして、非常に使い勝手がいいので、今まで使っていたBoostNoteからそちらに移行しました。 その際に、BoosteNoteのデータを全部マークダウンとしてエクスポートしたいのですが、1個づつでしかできません。 本来BoostNoteからしかデータへはアクセスできず、ディスク上に保存されるファイルは乱数のような名前です。 中身もマークダウンではなくcsonと呼ばれるJSONCoffeeScriptが合体したようなデータでした。

ということで、マークダウンを抽出するスクリプトを書きました。


使い方

コードgithub上に置いてありますのでcloneしていただくか、コピペして依存モジュールを手動でインストールしてください。

git clone git@github.com:dorapon2000/boostnote2markdown.git
pip install -r requirements.txt
python boostnote_to_markdown.py

フォルダ選択のダイアログが開くので、BoostNoteのワーキングディレクトリを指定してください。ワーキングディレクトリ内にmarkdownというディレクトリができて、その中にフォルダ構造を維持したままマークダウンがエクスポートできています。

コード

github.com

github上にコードがあります。

BoostNoteは./boostenote.jsonにフォルダ情報、./notes/*.csonにノートが保存されています。*.csonには親フォルダ名とデータがcson形式で保存されています。初めて聞いた形式だったのですが、以下のサイトに簡単な説明があります。

blog.kazu69.net

csonを読むモジュールはないかなと探したら、pycsonというドンピシャなものがあったのでこちらで読み取りました。使い方もjsonモジュールとほぼ同じで助かりました。

*.csonからデータ部分だけ取り出したら、BoostNote上のフォルダ構造を再現しながらマークダウンファイルに変換するだけです。 *.csonにかかれている親フォルダ情報(088f99dbeb2ee050cc8bみたいな)は記号なので、boostenote.jsonから記号に対応するフォルダ名を取得します。

注意点

作成するマークダウンの名前はBoostNote上のタイトルとなりますが、特殊記号が使われている場合適当な文字に変換しています。

特殊文字というのは「 \/:,*?<>|」で、Windowsでファイル名に使えないものです。 私の場合、論文名をそのままタイトルにしたり日付を入れたものがあるので、「:」や「/」が引っかかりました。 記号は[colon]や[slash]というふうに置換して、とりあえずマークダウンは作成してもらうようにしています。 削除するなり適宜あとで直してください。

import os
import re
import json
import cson
import tkinter
import tkinter.filedialog


def convert_to_name(dir_key, conf):
    """Convert from directory key  to directory name
    :param  str dir_key:    key in boostnote.json/folders/key
    :param  dict    conf:   dictionary converted from boostnote.json
    :rtype: str
    :return: directory name
    """

    return [meta['name'] for meta in conf['folders'] if meta['key'] == dir_key]


def sanitize(str_):
    """Sanitize string for Windows
    target: \\/:,*?<>|
    :param  str str_:   string you want to sanitize
    :rtype: string
    :return:    sanitized string
    """

    if re.search('[\\/:,*?<>|]', str_) is None:
        return str_

    str_ = str_.replace('\\', '[backslash]')
    str_ = str_.replace('/', '[spash]')
    str_ = str_.replace(':', '[colon]')
    str_ = str_.replace(',', '[hyphen]')
    str_ = str_.replace('*', '[star]')
    str_ = str_.replace('?', '[question]')
    str_ = str_.replace('<', '[less]')
    str_ = str_.replace('>', '[greater]')

    print(f'"{str_}" is sanitized')

    return str_


def extract_md_from_BoostNote():
    """Extract Markdown from BoostNote
    """

    cnt_success = 0
    cnt_skip = 0

    root = tkinter.Tk()
    root.withdraw()
    msg = 'Select your BoostNote working directory'
    boostnote = tkinter.filedialog.askdirectory(title=msg)
    conf_json = os.path.join(boostnote, 'boostnote.json')
    with open(conf_json) as f:
        conf = json.load(f)

    notes = os.path.join(boostnote, 'notes')
    for file in os.listdir(notes):
        with open(os.path.join(notes, file)) as f:
            note = cson.load(f)

            if note['type'] != 'MARKDOWN_NOTE':
                cnt_skip += 1
                continue

            key = note['folder']
            folder = convert_to_name(key, conf)
            title = note['title']
            content = note['content']

            if note['isTrashed']:
                folder = 'Trash'

        folder = sanitize(folder)
        title = sanitize(title)

        output_dir = os.path.join(boostnote, 'markdown', folder)
        os.makedirs(output_dir, exist_ok=True)
        output_file_name = title + '.md'
        output_file = os.path.join(output_dir, output_file_name)

        with open(output_file, 'w') as f:
            f.write(content)

        cnt_success += 1

    print('=============================================')
    print('Converting BoostNote to Markdown is Success!!')
    print(f'success: \t{cnt_success}')
    print(f'skip:    \t{cnt_skip}')


if __name__ == '__main__':
    extract_md_from_BoostNote()

Ubuntu 16.04でsudoとsuができなくなった問題

ubuntuをスリープから起こしたら、ターミナルの色のついた文字だけが表示されていない状態でした。 ターミナル再起動してもシェルを変えても治らないので、PCを再起動して直したんですが、そしたら今後はsudoが使えないという...

Ubuntuはデフォルトでsuが使えないようなので、管理者権限で実行する手段がなくなります。

環境

  • Ubuntu16.04

事象

$ sudo ls
[sudo] dorapon のパスワード:
dorapon は sudoers ファイル内にありません。この事象は記録・報告されます。

$ su
パスワード: 
su: 認証失敗

解決方法

How to Fix "Username is not in the sudoers file. This incident will be reported" in Ubuntu

こちらのサイトにまさに求めていた答えが書いてありました。 単純にsudoersファイルが壊れてしまったようですね。 Ubuntuリカバリモードで起動して、ユーザにsudo権限を与えます。

以下は上記のサイトの手順に沿って進めます。 画像は上記のサイトから拝借致しました。


PCを再起動してブート画面でAdvanced options for Ubuntuを選びます。ブート画面へは起動中にShiftキー長押しでいけます。

f:id:dorapon2000:20181025141358p:plain

recovery modeを選びます。自分のときはバージョン違いで2つあったんですが、新しい方のバージョンでやりました。

f:id:dorapon2000:20181025141819p:plain

Recovery menuでrootを選びます。ここからシェルモードに移ります。

f:id:dorapon2000:20181025142020p:plain

Press Enter for maintenanceと出るのでEnter押します。

参考サイトではいくつか方法を示されていましたが、コマンド打つだけの簡単な方法を実行しました。usernameには存在する自身のユーザ名を入れてください。

# mount -o rw,remount /
# adduser username sudo
# exit 

resume -> OKと進み、再起動すると無事sudoが使えるようになっています。

f:id:dorapon2000:20181025142731p:plain f:id:dorapon2000:20181025142745p:plain

🎉🎉

参考サイト

Ubuntu日本語フォーラム / 管理者としての権限が必要な操作でのパスワードが通らなくなりました

qiita.com

ns3.29のcodelのサンプルコードでSojournTimeを正しくトレーシングできない

正確には、ns-3-dev-git/codel-vs-pfifo-asymmetric.cc at master · nsnam/ns-3-dev-git · GitHubのSojournTimeを正しくトレーシングできません。その値をトレーシングしない以外は正常に動いていました。

特定の値の推移を記録できるトレーシングの仕組みについては、公式チュートリアルに詳しい説明があります。

環境

問題

github.com

codel-vs-pfifo-asymmetric.ccはns3に同封されているサンプルコードで、CoDelの性能評価することができます。 特にDroppingState・SojournTime・QueueLengthなどCoDelの性質を知るために必要な値をトレースできます。

問題は、SojournTimeだけなぜか出力ファイルが空白になってしまっていることです。 本来ならばcodel-vs-pfifo-fast-asymmetric-CoDel-sojourn.trにSojournTimeの値が時系列順に列挙されているはずです。

しかし、それ以外のトレースソースについては値をトレースできていますし、プログラム自体もエラーを出しません。

むむむ🤔

修正場所

2箇所修正すべき箇所があります。

$ diff -u codel-vs-pfifo-asymmetric.cc.orig codel-vs-pfifo-asymmetric.cc
--- codel-vs-pfifo-asymmetric.cc.orig   2018-10-12 00:50:29.826270000 +0900
+++ codel-vs-pfifo-asymmetric.cc        2018-10-12 00:51:16.568112000 +0900
@@ -92,9 +92,9 @@
 }

 static void
-SojournTracer (Ptr<OutputStreamWrapper>stream, Time oldval, Time newval)
+SojournTracer (Ptr<OutputStreamWrapper>stream, Time val)
 {
-  *stream->GetStream () << oldval << " " << newval << std::endl;
+  *stream->GetStream () << val << std::endl;
 }

 static void
@@ -109,7 +109,7 @@
   else
     {
       Ptr<OutputStreamWrapper> stream = ascii.CreateFileStream (sojournTrFileName.c_str ());
-      Config::ConnectWithoutContext ("/NodeList/2/$ns3::TrafficControlLayer/RootQueueDiscList/0/$ns3::CoDelQueueDisc/Sojourn", MakeBoundCallback (&SojournTracer, stream));
+      Config::ConnectWithoutContext ("/NodeList/2/$ns3::TrafficControlLayer/RootQueueDiscList/0/$ns3::CoDelQueueDisc/SojournTime", MakeBoundCallback (&SojournTracer, stream));
     }
 }

1箇所目は、Sojournというトレースシンク名で、正しくはSojournTimeでした。

  • SojournTime: Sojourn time of the last packet dequeued from the queue disc Callback signature: ns3::Time::TracedCallback

@ ns-3: ns3::CoDelQueueDisc Class Reference

2箇所目は、SojournTimeのコールバック関数のシグネチャが違いました。 上の記述にもCallback signature: ns3::Time::TracedCallbackとありますが、このシグネチャは引数を1つしか持ちません。

typedef void(* ns3::Time::TracedCallback) (Time value)

@ ns-3: ns3::Time Class Reference

当のコールバック関数SojournTracerはstreamと合わせて引数が2つじゃないかと思われるかもしれませんが、streamはns3の便利機能の1つで、いわばおまけです。 MakeBoundCallbackでファイルストリームをコールバック関数に渡すことでファイルに結果を出力してくれます。

過去の情報が修正されずに残ってしまったという感じでしょうか。

出力結果の可視化

トレース結果はgnuplotなどで可視化したいので、下に示すコードのように、時刻の値とsojournTimeの値を並べて出力するのがいいと思います。

static void
SojournTracer (Ptr<OutputStreamWrapper>stream, Time val)
{
  *stream->GetStream () << Simulator::Now ().GetSeconds () << " " << val.GetMilliSeconds() << std::endl;
}

Ubuntu 16.04 LTS で ns3.29 をインストールする

ns3.29が2018年9月4日にリリースされました。 ns3は1年に1回というペースでバージョンアップを繰り返しています。 早速自分もインストールしてみました。 以下では全部のせ(ns-allinone-3.29)のインストールをします。

エラーを被りながら、右往左往して得た最短ルートをうろおぼえで書いています。 間違っていたらコメントで指摘してくださると助かります。

環境

プレインストール

ns3のインストールの前に、必要なパッケージをaptコマンドでインストールしていきます。

$ sudo apt update
$ sudo apt upgrade

とりあえず、Installation - Nsnamに従って必要なパッケージをすべて入れます。 16.04でない環境の方は若干違うので、詳細はリンクを参照してください。

sudo apt install gcc g++ python python-dev
sudo apt install mercurial python-setuptools git
sudo apt install qt5-default
sudo apt install gir1.2-goocanvas-2.0 python-gi python-gi-cairo python-pygraphviz python3-gi python3-gi-cairo python3-pygraphviz gir1.2-gtk-3.0 ipython ipython3  
sudo apt install openmpi-bin openmpi-common openmpi-doc libopenmpi-dev
sudo apt install autoconf cvs bzr unrar
sudo apt install gdb valgrind 
sudo apt install uncrustify
sudo apt install doxygen graphviz imagemagick
sudo apt install texlive texlive-extra-utils texlive-latex-extra texlive-font-utils texlive-lang-portuguese dvipng
sudo apt install python-sphinx dia 
sudo apt install gsl-bin libgsl2 libgsl-dev
sudo apt install flex bison libfl-dev
sudo apt install tcpdump
sudo apt install sqlite sqlite3 libsqlite3-dev
sudo apt install libxml2 libxml2-dev
sudo apt install cmake libc6-dev libc6-dev-i386 libclang-6.0-dev llvm-6.0-dev automake
pip install cxxfilt
sudo apt install libgtk2.0-0 libgtk2.0-dev
sudo apt install vtun lxc
sudo apt install libboost-signals-dev libboost-filesystem-dev

ns3のダウンロード

以下はほぼGetting Started — Tutorialの翻訳みたいなもの。

ホームディレクトリを汚したくない方はワーキングディレクトリを作成してそちらにインストールしてください。 ns3のダウンロードにはいくつか方法がありますが、ここではbakeを使います。 別の方法としてtarballをダウンロードしてからインストールする方法もあるのですが、私の環境ではエラーが出てしまいました。

$ cd
$ mkdir workspace
$ cd workspace
$ hg clone http://code.nsnam.org/bake

bakeというディレクトリが作成されます。

$ ls bake
bake                  bakeconf.xml  doc       generate-binary.py  TODO
bake.py               examples      test

一時的にbakeディレクトリへのプログラムパスを通します。

cd bake
export BAKE_HOME=`pwd`
export PATH=$PATH:$BAKE_HOME:$BAKE_HOME/build/bin
export PYTHONPATH=$PYTHONPATH:$BAKE_HOME:$BAKE_HOME/build/lib

bakeを用いてns3をダウンロードします。 ns-allinone-3.29の部分のバージョン番号を直せば特定のバージョンを入れられます。 また、必要最低限のns3パッケージだけでいい場合は-e ns-3.29として下さい。

$ ./bake.py configure -e ns-allinone-3.29
$ ./bake.py check
$ ./bake.py download

sourceというディレクトリが新しくできます。

$ ls source
BRITE          netanim-3.108  openflow-ns-3.25  pygccxml-1.9.1
castxml        ns-allinone-3.29        pybindgen         v1.9.1.tar.gz
click-ns-3.25  nsc-0.5.3      pygccxml

ns3のビルド

ns3のビルドをします。

$ ./bake.py build

ns3のテスト

ns3に同封されているテストコードを実行して正常に動くか確認します。

$ cd ns-allinone-3.29
$ ./test.py

30分くらいかかりました。

最後にns3のサンプルスクリプトを動かしてみます。

$ ./waf --run hello-simulator
Hello Simulator

Hello Simulatorと表示されれば無事ns3.29のインストールは完了です。 お疲れ様でした。

参考

ネットワークシミュレータ ns-3.28 を Ubuntu 16.04 にインストール - ハードでもソフトウェア http://orsnken.hatenablog.com/

※記事のURLを貼るとバグるのでサイトトップページのURLで失礼します。

gnuplotほどよく必要最低限まとめ

実験で出たデータを手っ取り早くグラフ化して確認したいときに毎度gnuplotでぐぐってる気がするので、自分のために必要最低限だけまとめておきます。

環境

インストール

$ sudo apt install gnuplot

実行

グラフ化したいデータファイルを次のように用意しました。

$ cat data.tr
# comment
# x y z
1 2 1
2 4 4
3 6 9
4 8 16
5 10 25
6 12 36
7 14 49
8 16 64
9 18 81
10 20 100

gnuplotスクリプトをファイルへ書きます。 今回はxとyの値を使ったグラフを出力します。zの値は使いません。

$ cat graph.plt
set xlabel "x"
set ylabel "y"
plot "data.tr" using 1:2 w lp title "y = x ^ 2"
set terminal png
set output "graph.png"
replot
  • xlabelylabelはx軸y軸のラベル名。

  • plot "data.tr"gnuplotの核で、そのファイルを読み込んでグラフにプロットする。

  • using 1:2は1行にある空白区切りの1個目(=x)の値をx軸、2個目(=y)をy軸の数字として読み取れという意味。

  • w lpwith linespointsの短縮形で折れ線グラフになる。

  • title "y = x ^ 2"はそのまま。

ここまでがgnuplotによる画面への出力/描画で、出力先をpngファイルへ切り替えて、ファイル名の指定、pngファイルへの再描画をそれ以下で行っています。

gnuplotコマンドに渡して実行してみます。

$ gnuplot graph.plt

f:id:dorapon2000:20181007082508p:plain

ファイルへの出力だけにしたい場合は、いきなり出力先をpngに切り替えておきます。 WSL上でgnuplotを動かす場合はこうしないとうまく動きませんでした。

$ cat graph.plt
set terminal png
set output "graph.png"
set xlabel "x"
set ylabel "y"
plot "data.tr" using 1:2 w lp title "y = x ^ 2"

指定できるグラフの種類

with ???
lines ライン表示
points データポイント表示
linespoints ラインとデータポイント表示(折れ線表示)
impulses インパルス表示
dots ドット表示
steps ステップ表示
errorbars 誤差グラフ
boxes 棒グラフ
boxerrorbars 誤差と棒グラフ

CSVファイル

ファイルの先頭にset datafile separator ","を入れることで区切り文字をカンマへ変更できます。

引数を渡す

$ gnuplot -e 'indir="input"; outdir="$OUTPUT_DIR"' myscript.plt
set terminal png
set output outdir."/my_plot.png"
plot indir."/my_data.dat"

.は文字列結合

参考

シェル芸入門忘備録

突然シェル芸が勉強したくなったので、勉強したコマンドたちをまとめました。 シェル芸を忘れた未来の自分と、シェルは使ってるけどシェル芸のコマンドは知らない人向けです。 説明はできるだけ省いて、上から実行結果を見ていくだけで内容とシェル芸の雰囲気がつかめるよう努めました。


実施環境

紹介するコマンド

  • man
  • seq
  • shuf
  • tac
  • rev
  • yes
  • bc
  • tr
  • cut
  • sort
  • uniq
  • sed
  • awk
  • xargs
  • grepオプション
  • lsオプション

man

基本のキ。ホームポジションから手を離さず使い方を思い出せる。

$ man man

seq

連番を生成。1からなので注意。

$ seq 10
1
2
3
4
5
6
7
8
9
10

0から生成。

$ seq 0 5
0
1
2
3
4
5

bashの機能でも似たようなことができる。

$ echo {1..10}
1 2 3 4 5 6 7 8 9 10

shuf

出力の順番をシャッフルする。

$ seq 5 | shuf
3
4
2
1
5

tac

逆順に表示。

$ seq 5 | tac
5
4
3
2
1

rev

各行の文字列をリバースする。

$ echo "いろはにほへと" | rev
とへほにはろい

yes

yを無限出力。

$ yes | head -5
y
y
y
y
y

文字を指定。

$ yes hello! | head  -5
hello!
hello!
hello!
hello!
hello!

bc

文字列を計算する。

$ echo "1+2*3" | bc
7

tr

置換。引数に空白""指定不可。

$ echo 1 2 11 10 2 | tr " " "\n"
1
2
11
10
2

$  echo 1 2 11 10 2 | tr "12" "ab"
a b aa a0 b

特定の文字列削除。

$ echo 1 2 11 10 2 | tr -d " "
1211102

cut

半角空白" "を区切り文字として3フィールド目を取得。区切り文字はデフォルトでタブ\t

$ echo 1 2 11 10 2 | cut -d" " -f3
11

-bでバイト目を取得。-cで文字目を取得だが、ubuntu@WSLではマルチバイト文字があるとエラーを吐いた。Macのcutは正しく動いた。

$ echo hello! | cut -b 2
e

$ echo hello! | cut -b 2-
ello!

sort

$ echo 1 2 11 10 2 | tr " " "\n" | sort
1
10
11
2
2

# --numeric-sort
$ echo 1 2 11 10 2 | tr " " "\n" | sort -n
1
2
2
10
11

# --reverse
$ echo 1 2 11 10 2 | tr " " "\n" | sort -nr
11
10
2
2
1

# --uniq
$  echo 1 2 11 10 2 | tr " " "\n" | sort -nu
1
2
10
11

uniq

重複削除

$ echo 1 2 11 10 2 | tr " " "\n" | sort -n | uniq
1
2
10
11

# --duplicated
$ echo 1 2 11 10 2 | tr " " "\n" | sort -n | uniq -d
2

# --count
$ echo 1 2 11 10 2 | tr " " "\n" | sort -n | uniq -c
     1 1
     2 2
     1 10
     1 11

sed

置換。

# ABC -> XYZ
sed 's/ABC/XYZ/g'

# 10行目~20行目で置換
sed '10,20s/ABC/XYZ/g'

# 2つ置換
sed -e 's/AAA/XXX/g' -e 's/BBB/YYY/g'

# AAAを含む行のBBBをCCCへ置換
sed -e '/AAA/s/BBB/CCC/g'

行の削除。

# 1行目削除
sed 1d

# 1~3行目削除
sed 1,3d

# #から始まる行を削除
sed '/^#/d'

文字の削除。

sed -e "s/ABC//g"

awk

ある種のプログラミング言語なので詳細は他のサイトに譲る。基本はawk PATTERN{ACTION}でif (PATTERN) ACTIONと捉えられる。

空白またはタブで区切られた5番目が10000以上のとき。

$ ls -l / | awk '$5 >= 10000 {print}'
-rwxr-xr-x  1 root root 87944 Jan  1  1970 init

$ ls -l / | awk '$5 >= 10000 {print $5}'
87944

ACTIONを省略すると{print}と同義。~は==の正規表現版。==はなぜか動かなかった。

$ ls -l / | awk '$6 ~ /Sep/'
drwxr-xr-x  1 root root   512 Sep 13 22:07 dev
dr-xr-xr-x 11 root root     0 Sep 13 22:07 proc
drwxr-xr-x  1 root root   512 Sep 13 22:07 run
dr-xr-xr-x 12 root root     0 Sep 13 22:07 sys
drwxrwxrwt  1 root root   512 Sep 12 22:00 tmp

PATTERNを省略すると全行に適応

$ ls -l / | awk '{print $1,$2,$3}' | head -5
total 88
drwxr-xr-x 1 root
drwxr-xr-x 1 root
drwxr-xr-x 1 root
drwxr-xr-x 1 root

$ ls -l / | awk '{print $1$2$3}' | head -5
total88
drwxr-xr-x1root
drwxr-xr-x1root
drwxr-xr-x1root
drwxr-xr-x1root

PATTERNには正規表現も可能

$ ls -l / | sed 1d | awk '/^[^d]/{print $9, "is not a directory"}'
init is not a directory

NRはNum of Recordsで現在行が入るawkの変数。NFもある。

ls -l / |  awk '/^[^d]/ && NR>1{print $9, "is not a directory"}'
init is not a directory

--field-separator。区切り文字をデフォルトの"[ \t]+"から":"に変更。-F","でCSVに使える。

$ cat /etc/passwd | awk -F":" '$7 ~ /bash$/{print $1}'
root
dorapon
  • ENDは最後に1回だけ実行されるPATTERN。BEGINもある。
  • PATERN{ACTION}は並べて複数書ける。
  • 仮想配列もある。ただし出力順番は不定
  • ACTION自身もセミコロン;で複数書ける。
  • for,while,case,ifも雰囲気で使える。
$ ls -l / | awk 'NR>1{month[$6] += $5} END{print "The sum of capacity of each month."; for(m in month) print m,month[m],"bytes"}'
The sum of capacity of each month.
Sep 1536 bytes
Jan 87944 bytes
Apr 5120 bytes
Jul 2560 bytes

xargs

空白タブ改行を一緒くたにまとめる。

$ echo "1 23\n4\t5 6  7\n\t89"
1 23
4       5 6  7
        89

$ echo "1 23\n4\t5 6  7\n\t89" | xargs
1 23 4 5 6 7 89

# 2行ごと改行出力
$ echo "1 23\n4\t5 6  7\n\t89" | xargs -L2
1 23 4 5 6 7
89

# 1行ごと
$ echo "1 23\n4\t5 6  7\n\t89" | xargs -L1
1 23
4 5 6 7
89

$ echo "1 23\n4\t5 6  7\n\t89" | xargs -L1 | tr " " "+" | bc
24
22
89

取得した複数のファイル名を1つづつ引数に取りたい時

$ grep -ils info /var/log/*
/var/log/dpkg.log

# xargsがないと出力自体を引数にとってしまう。
$ grep -ils info /var/log/* | tail -3
/var/log/dpkg.log

$ grep -ils info /var/log/* | xargs tail -3
2018-09-06 22:47:28 trigproc man-db:amd64 2.8.3-2 <none>
2018-09-06 22:47:28 status half-configured man-db:amd64 2.8.3-2
2018-09-06 22:47:33 status installed man-db:amd64 2.8.3-2

# 実際に実行するコマンドは-tオプションで見られる。
$ grep -ils info /var/log/* | xargs -t tail -3
tail -3 /var/log/dpkg.log
2018-09-06 22:47:28 trigproc man-db:amd64 2.8.3-2 <none>
2018-09-06 22:47:28 status half-configured man-db:amd64 2.8.3-2
2018-09-06 22:47:33 status installed man-db:amd64 2.8.3-2

便利なオプション

grep

オプション 説明
-r, --recursive 再帰的に探索 grep Error -r /var/log
-i, --ignore-case 大文字小文字区別なし grep Error -ri /var/log
-l, --files-with-matches ファイル名だけ出力 grep Erro -rl /var/log
-e, --regexp 正規表現
-o, --only-matching 一致した文字を出力 grep -e -o "eth[0-9]\+" hoge.log
-v, --invert-match を含まない grep -v 0 dropstats.log
-s, --nomessages エラー出力なし

ls

オプション 説明
-1 1行で表示 ls -1
-t 更新時間順 ls -lt
-S サイズ順 ls -lS
-F ディレクトリの後ろに/ ls -lF

乱数生成

bash環境変数$RANDOMを使う場合。ただし、0~32767。

$ echo $((RANDOM%+101))
47

連続で

$ yes 'echo $((RANDOM%+101))' | head -5 | bash
21
60
50
70
88

/dev/urandomを使う場合。

echo $(($(od -vAn -N1 -tu < /dev/urandom) % 101 ))
99

参考サイト

用語集:ランダム・乱数まとめ: UNIX/Linuxの部屋

AWKのトリッキーな配列&連想配列の仕組み・動作と目からウロコのテクニック (1/2):CodeZine(コードジン)