My Profile Photo

安心院日記


猫になりたい。趣味で運用しているブログです。技術的な備忘録・やったことメモとポエム置き場。


moreutilsについて学ぶ

今日、ふとしたことで moreutils というものの存在を知った。ニッチだが使いこなすと便利そうなコマンド郡だったので一通りすべて触ってみることにする。最近お仕事で shell のワンライナーを書くことが多々あるので有効活用するぞ。

今回扱うのはCentOS7で入る moreutils にする。Ubuntuでも多分同じ中身だろう(未確認)

かなり参考にしました。アウトプットのために内容が被っていても投稿

$ sudo yum install moreutils
$ rpm -qi moreutils
Name        : moreutils
Version     : 0.49
Release     : 2.el7
Architecture: x86_64
Install Date: Tue 13 Nov 2018 03:55:29 AM JST
Group       : Applications/System
Size        : 155340
License     : GPLv2
Signature   : RSA/SHA256, Tue 04 Mar 2014 12:35:02 PM JST, Key ID 6a2faea2352c64e5
Source RPM  : moreutils-0.49-2.el7.src.rpm
Build Date  : Wed 26 Feb 2014 07:58:44 PM JST
Build Host  : buildvm-21.phx2.fedoraproject.org
Relocations : (not relocatable)
Packager    : Fedora Project
Vendor      : Fedora Project
URL         : http://kitenet.net/~joey/code/moreutils/
Summary     : Additional unix utilities
Description :
 This is a growing collection of the unix tools that nobody thought
 to write thirty years ago.

 So far, it includes the following utilities:
 - isutf8: check if a file or standard input is utf-8
 - sponge: soak up standard input and write to a file
 - ts: timestamp standard input
 - vidir: edit a directory in your text editor
 - vipe: insert a text editor into a pipe
 - combine: combine the lines in two files using boolean operations
 - ifdata: get network interface info without parsing ifconfig output
 - pee: tee standard input to pipes
 - zrun: automatically uncompress arguments to command
 - mispipe: pipe two commands, returning the exit status of the first
 - lckdo: execute a program with a lock held
 - ifne: run a program if the standard input is not empty
 - parallel: run multiple jobs at once (contained in moreutils-parallel sub package)
 - chronic: runs a command quietly, unless it fails

command

rpm -qi moreutils の簡易説明
雰囲気概要和訳

使用例

のような形で書いていく。

isutf8

check if a file or standard input is utf-8
ファイルか標準入力が utf-8 であるか判定する

$ echo "日本語" | isutf8 ; echo $?
0

$ echo "日本語" | nkf -Ws | isutf8 ; echo $?
stdin: line 1, char 1, byte offset 6: invalid UTF-8 code
1

文字コードがutf8でないファイルにだけ特定の処理をするとか

$ ls
0.txt  1.txt  2.txt  3.txt  4.txt  5.txt  6.txt  7.txt  8.txt  9.txt

$ file *
0.txt: Non-ISO extended-ASCII text
1.txt: UTF-8 Unicode text
2.txt: UTF-8 Unicode text
3.txt: UTF-8 Unicode text
4.txt: UTF-8 Unicode text
5.txt: UTF-8 Unicode text
6.txt: UTF-8 Unicode text
7.txt: Non-ISO extended-ASCII text
8.txt: UTF-8 Unicode text
9.txt: UTF-8 Unicode text

$ for FILE in `ls`; do isutf8 $FILE 1>/dev/null || echo $FILE; done
0.txt
7.txt

sponge

soak up standard input and write to a file
標準入力を全て受け取った後にファイルへ出力する(標準出力も可)

$ cat file1
1
8
9
4
$ cat file1 | sort > file1
$ cat file1
(empty)

$ cat file2
1
8
9
4
$ cat file2 | sort | sponge file2
$ cat file2
1
4
8
9

早速だがワンライナーでの使用例が思いつかない。使い捨てのワンライナーでわざわざ入力と出力を同じファイルにする理由があるのだろうか。

ts

timestamp standard input
標準入力で受け取った各行にタイムスタンプを追加して出力する

$ seq 5 | ts
Nov 16 00:05:01 1
Nov 16 00:05:01 2
Nov 16 00:05:01 3
Nov 16 00:05:01 4
Nov 16 00:05:01 5

strftime形式で指定するとそのフォーマットで出力する。 "%.S" でより細かい時間を確認できる

$ seq 5 | ts "%H:%M:%.S"
00:25:36.169158 1
00:25:36.169227 2
00:25:36.169265 3
00:25:36.169299 4
00:25:36.169333 5

-r オプションで現在との差分を確認できる。ログを読むのが楽になるかもしれない

$ sudo tail /var/log/secure
()
Nov 16 00:29:17 localhost sudo:     cat : TTY=pts/16 ; PWD=/home/cat/workspace/tmp ; USER=root ; COMMAND=/bin/tail /var/log/secure
Nov 16 00:29:47 localhost sudo:     cat : TTY=pts/16 ; PWD=/home/cat/workspace/tmp ; USER=root ; COMMAND=/bin/tail /var/log/secure

$ sudo tail /var/log/secure | ts -r
()
36s ago localhost sudo:     cat : TTY=pts/16 ; PWD=/home/cat/workspace/tmp ; USER=root ; COMMAND=/bin/tail /var/log/secure
6s ago localhost sudo:     cat : TTY=pts/16 ; PWD=/home/cat/workspace/tmp ; USER=root ; COMMAND=/bin/tail /var/log/secure
right now localhost sudo:     cat : TTY=pts/16 ; PWD=/home/cat/workspace/tmp ; USER=root ; COMMAND=/bin/tail /var/log/secure

vidir

edit a directory in your text editor
ディレクトリやファイルの名前をテキストエディタ経由で編集できる

$ ls
1  2  3  4  5
$ vidir

1       ./1
2       ./2
3       ./3
4       ./4
5       ./5

↓ 編集して終了(:wq)

1       ./1001
2       ./1002
3       ./1003
4       ./1004
5       ./1005

$ ls
1001  1002  1003  1004  1005

例えば、深いディレクトリに隠れているファイル達に対してそのパスをprefixとしてつけつつmvすることができる。

$ ls
1  out
$ ls 1/*/*
1/1/a  1/1/b  1/1/c  1/2/a  1/2/b  1/2/c
$ vidir 1/*/*

1       ./1/1/a
2       ./1/1/b
3       ./1/1/c
4       ./1/2/a
5       ./1/2/b
6       ./1/2/c

↓ 編集して終了(:wq)

1       out/1-1-a
2       out/1-1-b
3       out/1-1-c
4       out/1-2-a
5       out/1-2-b
6       out/1-2-c


$ ls out/
1-1-a  1-1-b  1-1-c  1-2-a  1-2-b  1-2-c
$ ls 1/*/*
ls: cannot access 1/*/*: No such file or directory

vipe

insert a text editor into a pipe
受け取った標準入力をテキストエディタで編集して次のパイプに渡すことができる

特に説明不要なので使用例だけ。

command1 | vipe | command2

combine

combine the lines in two files using boolean operations
2つのファイルの中身をブール演算を用いて結合する

$ cat a.txt
banana
apple
orange

$ cat b.txt
banana
suica
orange
strawberry

$ combine a.txt and b.txt
banana
orange

$ combine a.txt not b.txt
apple

$ combine a.txt or b.txt
banana
apple
orange
banana
suica
orange
strawberry

$ combine a.txt xor b.txt
apple
suica
strawberry

diff を取ってから差分を取り回していたのが直接できるかな。

ifdata

get network interface info without parsing ifconfig output
ネットワーク情報を簡潔な形式で出力する

他にもオプションが大量にある。インターフェイス名は ifdata で取得できないので予め把握しておくか、 ip link show 等で持ってくる必要がある

$ ifdata -pa eth0
10.0.2.15

pee

tee standard input to pipes
標準入力を受け取りパイプに流す tee

説明からは分かりづらいが、受け取った標準入力を複数のパイプに流すことができる。その際は | でパイプを書くのではなく引数にコマンドとして実行する文字列を渡す。 tee は標準入力を標準出力とファイル出力の2つに流すが、 pee は複数のパイプに流せる、ということか。

$ echo "12345" | pee "xargs echo" "rev | xargs echo" "factor"
12345
54321
12345: 3 5 823

zrun

automatically uncompress arguments to command
引数に渡された圧縮ファイルを自動で展開してコマンドを実行する

対応している拡張子は gz, bz2, xz, lzma, lzo

展開した一時ファイルは /tmp に作成される模様

$ ls
file.gz

$ zrun cat file.gz
abcde
12345
QWERT
%&#~=

$ ls
file.gz

mispipe

pipe two commands, returning the exit status of the first
2つのコマンドをパイプでつなげるが、終了ステータスは1番目のコマンドの値を返却する

$ mispipe "echo hoge; exit 1" "xargs echo" ; echo $?
hoge
1

lckdo

execute a program with a lock held
ロックを掛けつつプログラムを実行する

マルチプロセスで同一のフィアルに変更を与えないようにファイルをロックすることができる。現在のLinuxには flock という同じことができるコマンドが存在するためdeprecatedになっている。

ifne

run a program if the standard input is not empty
標準入力が空でない場合にコマンドを実行する

$ echo -n "" | ifne date

$ echo -n "hoge" | ifne date
Fri Nov 16 09:43:23 JST 2018

ifne には -n オプションがあり、つけると挙動が逆転する。ただし、本来の標準出力が出力される模様

$ echo -n "" | ifne -n date
Fri Nov 16 09:44:55 JST 2018

$ echo -n "hoge" | ifne -n date
hoge

parallel

run multiple jobs at once (contained in moreutils-parallel sub package)

パッケージには含まれているようだが、コマンド自体は存在しなかった。謎

chronic

runs a command quietly, unless it fails
コマンドを実行し、失敗した場合のみ標準出力と標準エラー出力に出力を行う

$ chronic sh -c "echo hoge; exit 1"
hoge

$ chronic sh -c "echo hoge; exit 0"