個人的なシェル芸(シェルワンライナー)のまとめ

個人的なシェル芸(シェルワンライナー)のまとめ

シェル芸botで遊んでいた際のシェル芸や、作業・仕事で使ったものでおもしろかったもの・便利だったものを雑に残していくページ。

とりあえず覚えといたほうがいいこと

とりあえず、ここに書いてある内容を把握するにあたって覚えといたほうがいいことをまとめてみる。

シェル芸ってなんぞ?

シェルのワンライナーのこと。

ちゃんとした定義もあるので、シェル芸と名前をつけてシェル芸勉強会を主催している上田先生のページより抜粋。

マウスも使わず、ソースコードも残さず、GUIツールを立ち上げる間もなく、あらゆる調査・計算・テキスト処理をCLI端末へのコマンド入力一撃で終わらすこと。あるいはそのときのコマンド入力のこと。

シェルの機能・使い方で覚えとくこと(主にbash)

よく使うシェルの機能と使い方について、軽くまとめておく。 微妙にカテゴリ違うものが混在してる気がするけど、とりあえずここでは気にしないことにする(´・ω・`)。

主にbashについて記述しているが、zshでのやり方についても少し触れる(あとたまにfish)。

標準入力・標準出力・標準エラー出力

(厳密にはシェルの機能じゃないけど、触れておかないとあとの説明でいきなり出そうなのでここで書く…)

(Windows系はよく知らんのだけど)UNIX系OSで共通の考え方として、プロセスに対する入力や出力を制御するためにファイルディスクリプタというものがある。 UNIX系の場合、OSが0(標準入力)、1(標準出力)、2(標準エラー出力)というものをプロセス立ち上げ時に開いてくれており、通常は/proc/$pid/fd/配下からアクセスできる様になっている。

基本的には以下の様な使い分けがされている。

  • 標準入力(0) ... プロセスへの入力データを受け付ける(受け付ける方法は色々あるが、キー入力やパイプから受け付けるなど)
  • 標準出力(1) ... プロセスの標準的な出力
  • 標準エラー出力(2) ... プロセスの標準的ではない出力(エラーとかログ出力に使われる事が多い)

参考

パイプ

|で記述する。 主に標準入力値をパイプでつなげたコマンドにわたすために使われる。

たとえば、以下のコマンドだとcommand1の標準出力をcommand2の標準入力に渡している。

command1 ... | command2 ...

実際のコマンドを使って記述してみる。 echo 123の標準出力は123になるが、それをsedに渡して置換処理をしている。

echo 123 | sed 's/1/4/'
$ echo 123
123

$ echo 123 | sed 's/1/4/'
423

リダイレクト

ファイルへの書き込みや読み込みを指定できる。

書き込み処理の書き方

基本的にこれだけ覚えてれば通常のコンソール操作では困らない気もする。 設定内容をファイルに書いたり、出力結果を適当なファイルに追記したりと色々なトコで使うと思う。

# 書き込み(上書き)
comamnd > file_path

# 書き込み(追記)
comamnd >> file_path

# 出力元のファイルディスクリプタ(FD)を指定
command 1> file_path # 標準出力のみをリダイレクト(デフォルト)
command 2> file_path # 標準エラー出力のみをリダイレクト
command &> file_path # 標準出力・標準エラー出力を共にリダイレクト

# 標準出力/標準エラー出力を入れ替える
command 3>&1 1>&2 2>&3

読み込み処理の書き方

ファイルの読み込みも行える。

# ファイルを読み込む
command < file_path

# `EOF`(文字列は指定可能)の行が出るまでを読み込む
# (Tabなどを受け付ける場合は`<<`ではなく`<<-`を使う)
command << EOF
111
222
333
EOF

# 文字列を標準入力で受け付ける(パイプと同様)
command <<< string

コマンド置換

コマンド置換は $(command) もしくは \`command\` といった形で指定することでコマンドの実行結果を差し込むことができる機能になる。

たとえば、以下のようにechoで呼び出す際にコマンド置換でdateを実行させるといったこともできる。

echo $(date +%Y%m%d).log
$ echo $(date +%Y%m%d).log
20200502.log

ちなみにbash,zshでは$(command)と記述するのだが、fishは(command)と書くので注意。 (インタラクティブシェルで$(command)で実行すると怒られるので気づくとは思うけど)

$ echo $(echo test)
fish: $(...) is not supported. In fish, please use '(echo)'.
echo $(echo test)
     ^

プロセス置換

>(command)<(command)といった書き方で、本来はファイルを指定する引数に実行コマンドを指定することができる。

少しわかりにくいのだが、使えるとかなり便利。 かんたんな例として、sortしていないファイルのdiff(diffコマンドは事前にファイルをsortしておく必要がある)を書いておく。

# sortしてdiffする
diff <(sort a.txt) <(sort b.txt)

ブレース展開

個人的に好きな機能。 {...}といった感じで記述することで、シェルがコマンド実行前に内容を解釈して展開してくれる。

基本的にはカンマ(,)区切りで指定した要素を展開するのだが、連続した要素(数字やアルファベットなど)であれば {a..z} といった感じで記述することができる。

$ # カンマ区切りで展開させる
$ echo {aaa,bbb,ccc,ddd,123}
aaa bbb ccc ddd 123
$
$ # 前後に文字を記述することで展開する要素にも適用する
$ echo x_{111,222,333,444}
x_111 x_222 x_333 x_444
$
$ # ブレース展開はネストすることも可能
$ echo x_{1{2,3,4},3}
x_12 x_13 x_14 x_3
$
$ # 複数のブレース展開を結合して記述することで、それぞれの組み合わせを取得できる
$ echo {a..c}_{1..3}
a_1 a_2 a_3 b_1 b_2 b_3 c_1 c_2 c_3
$
$ # 連続する要素は`..`で指定できる
$ echo {0..9}
0 1 2 3 4 5 6 7 8 9
$ echo {a..e}
a b c d e
$
$ # 連続する要素の間隔も指定できる
$ echo {0..9..3}
0 3 6 9

ちなみに、zshの場合は日本語(ひらがなとか)を連続する要素として指定する事もできる。 これはzshだけの挙動でbashでは動作しない。

$ echo {あ..お}
あ ぃ い ぅ う ぇ え ぉ お

ちなみにfishでは..で連続して展開する方法自体が使用出来ない(カンマ区切りでの展開は可能)。

三項演算子

他の言語でもある三項演算子っぽい記述方法。 &&のあとに前のコマンドが正常終了時の処理を、||のあとに異常終了時の処理を続けて記述できる。

command1 ... && command1正常終了時の処理 || command1異常終了時の処理
$ # 正常終了時に`echo 0`
$ echo test && echo 0 || echo 1
test
0
$
$ # 異常終了時に`echo 1` (コマンド実行時に!を頭につけると終了ステータスを反転できる)
$ ! echo test && echo 0 || echo 1
test
1

グルーピング

コマンドを(...){...}で囲むことで、ひとまとめのグループとして扱う。 リダイレクトの際にひとかたまりのコマンドとして扱わせたりすることができる。

# command1,command2の出力をまとめてcommand3にわたす
( command1;command2; ) | command3
{ command1;command2; } | command3

Glob展開

*(アスタリスク)で、PATHをワイルドカード検索する機能。 echoなどでも展開が行われる。

コマンド実行前に解釈されるので、もし*を引数に入れる場合は\でエスケープするかクォーテーションで囲んでやる必要がある。

エスケープシーケンス

キーボードで入力できない制御文字(nullキャラクタや改行、タブなど)やターミナルでの出力のカラー指定、カーソル移動などを指定するためのもの。 いくつか例を抜粋する。

# nullキャラクタ
echo "\0"

# 改行
echo "\n"

# タブ
echo "\t"

# testの色を赤くする
echo -e "\e[31mtest\e[30m"

変数展開

bashの機能として、変数展開時の記述の仕方で、変数の値を置換や抜き出すことができる。

$ TEST=123456789
$ echo ${TEST}
123456789
$
$ # 変数の文字数を取得
$ echo ${#TEST}
9
$
$ # 後ろから3文字抜き出す
$ echo ${TEST: -3}
789
$
$ # 後ろから3文字消す
$ echo ${TEST::-3}
123456

以下、書き方と処理内容の一覧。

パラメータ展開 機能
${#変数} 変数の文字数を取得する
${変数:-文字列} 変数がNULLの場合、指定した文字列を返す
${変数:+文字列} 変数がNULL以外の場合、指定した文字列を返す
${変数:=文字列} 変数がNULLの場合、変数に指定した文字列を代入する
${変数:?文字列} 変数がNULLの場合、指定した文字列を返しエラー終了する
${変数#文字列} 変数より、前方から最短一致した箇所を除外する(基本ワイルドカード組み合わせ要)
${変数##文字列} 変数より、前方から最長一致した箇所を除外する(基本ワイルドカード組み合わせ要)
${変数%文字列} 変数より、後方から最短一致した箇所を除外する(基本ワイルドカード組み合わせ要)
${変数%%文字列} 変数より、後方から最長一致した箇所を除外する(基本ワイルドカード組み合わせ要)
${変数:N} 変数より、N文字以降の文字のみ抽出する
${変数:N:X} 変数より、N文字目からX個の文字を抽出する
${変数: -N} 変数より、後ろからN文字のみ抽出する
${変数: -N:X} 変数より、後ろからN文字、X個の文字のみ抽出する
${変数::N} 変数より、頭からN文字のみ抽出する
${変数::-N} 変数より、後ろからN文字除外する
${変数/置換前/置換後} 変数の内容を、置換前文字列を置換後文字列に変換して返す
${変数^[文字列]} 変数の一文字目を大文字にする(文字列を指定してる場合はその文字列のみを対象にする)
${変数^^[文字列]} 変数全体を大文字にする(文字列を指定してる場合はその文字列のみを対象にする)
${変数,[文字列]} 変数の一文字目を小文字にする(文字列を指定してる場合はその文字列のみを対象にする)
${変数,,[文字列]} 変数全体を小文字にする(文字列を指定してる場合はその文字列のみを対象にする)
${!文字列*} 指定された文字列から始まる変数を取得する

算術式展開

bashでは、$((...))といった記述をすることで、中の式の計算結果を出力して利用できる。 ただ、小数点以下の計算はできないので注意。

$ # 基本的な四則演算ができる
$ echo $((1+2))
3
$ echo $((1+2*3))
7
$
$ # 乗数は`**`で計算する
$ echo $((2**3))
8

入れとくと便利なコマンド

どの環境でも適切に動くように記述するのもいいのだけど、シェル芸の場合自分の環境で書き捨てのコードをチャチャっと書いて処理を終わらせるためのものという意味合いもある。 なので「どの環境でも」それこそ商用UNIXとかであっても、POSIX準拠の環境であれば同じ動作をするように記述するという考え方もあるのだけど、ここではそういうふうな認識でコマンドを書いてない。

で、あくまでもここでは自分の環境でコマンドを実行することを想定しているので、「自由にコマンド入れられると仮定して」シェル芸で処理をする際に入れとくと便利なコマンドを列挙しとく。 順不同、かつ一般的なディストリやMacでバンドルされてそうなコマンド、よくインストールされるであろうコマンド(nkfとか)は書かない。

コマンド 概要
rs 文字列の縦横変換などをオプション指定でできる。
datamash 文字列の縦横変換などをオプション指定でできる。
uconv ひらがな⇔ローマ字変換などをしてくれる。

シェル芸botで遊んでたやつ

シェル芸botで遊ぶ際に作成したシェル芸について残しておく。

シェル芸botってなに?

ふるつきさんの作ってるOSSで、コマンドを渡したらNWにつながってないDocker内で処理して結果をツイートしてくれる。

シェル芸botでよく使われている(有志の)コマンド

シェル芸botはオープンソースということもあって、利用者から自作のコマンドをプルリクされて追加されてることが多々ある。

その中でもよく使われているコマンドを抜粋する。

  • echo-sd ... 引数に文字列を指定すると、その文字列を叫ぶ吹き出しに入れて出力してくれるコマンド(シェルスクリプト)。いろんなオプションがある。
  • textimg ... パイプか引数で受け付けた内容を画像やgifファイルにして出力してくれるコマンド。ターミナルのカラーコードや絵文字も解釈して画像化してくれる。

echo-sdをネストする(パイプにつなげるコマンドをネスト)

要は、こんな感じでecho-sdの中に値を繰り返す処理をするシェル芸。

echo あいうえお | echo-sd -s | echo-sd -s | echo-sd -s

こういう場合の処理を短く書くには、以下のようにブレース展開とevalを組み合わせて使うといい感じに短縮できる(eval使うのってどうなのってツッコミはとりあえず置いといて)。

echo あいうえお | eval 'echo-sd -s |'{,,,} cat
$ echo あいうえお | eval 'echo-sd -s |'{,,,} cat
_人人人人人人人人人人人人人人人人人人人_
> _人人人人人人人人人人人人人人人_ <
> > _人人人人人人人人人人人_ < <
> > > _人人人人人人人_ < < <
> > > > あいうえお < < < <
> > >  ̄Y^Y^Y^Y^Y^Y^Y^ ̄ < < <
> >  ̄Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^ ̄ < <
>  ̄Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^ ̄ <
 ̄Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^ ̄

hashのストレッチングとかをイメージしてもらえるとわかりやすいかも?

echo-sdでだんだんとネストさせるgifを生成する

応用例。 echo-sdを何度もネストさせるようなgifを生成させる場合の処理。 (だいぶ汚いので、もうちょっとキレイに書いたほうが良いかもしれない…)

seq -f 'echo ごはんたべたい | eval $(printf "echo-sd -s|"%%.s {1..%g}) cat' 6 | awk '{print $0"|eval sed $(printf -- \"-e{\\\\\\$a,1i}  \"%.s {1.."6-NR"}) -e\s/^/$(printf \"  \"%.s {1.."6-NR"})/g"}' | head -n -1 | bash | textimg -sal 13

echo-sdで1文字づつ囲ませる

特定の文字列に対して、左から一文字づつecho-sdで囲んだ文字列を出力する。

$ seq 5 | xargs -I@ bash -c 'echo あいうえお | sed -r "s/./\necho-sd &っ!\n/@" | sed '\''/echo-sd/!s/^/echo -e \\\\n/g;;s/^/<(/g;s/$/)/g'\'' | eval paste $(paste - - -) | sed '\''s/\t//g;2!s/^/'\''$(printf " %.s" {1..@})'\''/g;s/^ //g'\'''
_人人人人人_
> あっ! <いうえお
 ̄Y^Y^Y^Y^Y^ ̄
 _人人人人人_
あ> いっ! <うえお
  ̄Y^Y^Y^Y^Y^ ̄
  _人人人人人_
あい> うっ! <えお
   ̄Y^Y^Y^Y^Y^ ̄
   _人人人人人_
あいう> えっ! <お
    ̄Y^Y^Y^Y^Y^ ̄
    _人人人人人_
あいうえ> おっ! <
     ̄Y^Y^Y^Y^Y^ ̄

さらにカスタムして、特定の文字列だけ2文字にして処理してみる(「伯方の塩」のCM風)。

seq 5 | xargs -I@ bash -c 'echo はかたのしお | sed -r "s/[^し]|しお/\necho-sd &っ!\n/@" | sed '\''/echo-sd/!s/^/echo -e \\\\n/g;;s/^/<(/g;s/$/)/g'\'' | eval paste $(paste - - -) | sed '\''s/\t//g;2!s/^/'\''$(printf " %.s" {1..@})'\''/g;s/^ //g'\'''
$ seq 5 | xargs -I@ bash -c 'echo はかたのしお | sed -r "s/[^し]|しお/\necho-sd &っ!\n/@" | sed '\''/echo-sd/!s/^/echo -e \\\\n/g;;s/^/<(/g;s/$/)/g'\'' | eval paste $(paste - - -) | sed '\''s/\t//g;2!s/^/'\''$(printf " %.s" {1..@})'\''/g;s/^ //g'\'''
_人人人人人_
> はっ! <かたのしお
 ̄Y^Y^Y^Y^Y^ ̄
 _人人人人人_
は> かっ! <たのしお
  ̄Y^Y^Y^Y^Y^ ̄
  _人人人人人_
はか> たっ! <のしお
   ̄Y^Y^Y^Y^Y^ ̄
   _人人人人人_
はかた> のっ! <しお
    ̄Y^Y^Y^Y^Y^ ̄
    _人人人人人人_
はかたの> しおっ! <
     ̄Y^Y^Y^Y^Y^Y^ ̄

キングウンコを生成する

キングウンコ、それはシェル芸botの偉大なるマスコット…!

2019年の1月頃に遊んでたら出来てしまったシロモノなのだけど、たまにこれを使って遊んでたりする。

叫べ!キングウンコ!!

一番カンタンにコンソール上に出す方法がこれ。

内部でecho-sdを呼んでる unko.shoutというシェルスクリプトがsuper_unkoに入ってる。 このコマンドに引数で文字列を与えると、その文字列をキングウンコが叫ぶ!

叫びます!(だからなんだ)

$ unko.shout ウンコおぉ!!
_人人人人人人人人人_
> ウンコおぉ!! <
 ̄Y^Y^Y^Y^Y^Y^Y^Y^Y^ ̄
      👑
    (💩💩💩)
   (💩👁💩👁💩)
  (💩💩💩👃💩💩💩)
 (💩💩💩💩👄💩💩💩💩)

このコマンド、もちろんシェル芸botにも入っているのでよかったら遊んでください(´・ω・`)。

unko.towerを用いて出力する場合

そもそも、このキングウンコはもともとはぐれさんの作ったunko.towerというコマンドの出力をベースに作成してるものなのだ。

$ unko.tower 4
      人
    (   )
   (     )
  (       )
 (         )

この出力のうんこの中の全角スペースに💩を詰めていき、そこに顔をつければ完成。 以下、この出力をもとに生成するコマンド。

unko.tower 4 | \
 sed -r ':a;s/(( *) /\1💩/;ta' | \
 sed -e'3s/💩/👁/'{2,3} -e'4s/💩/👃/4' -e'5s/💩/👄/5' -e'1s/人/👑/'

ちなみにunko.towerも日々進化してて、現行バージョンだと-sオプションを使うことでもっと短縮できる。

unko.tower -s 💩 4 | sed -e'3s/💩/👁/'{2,3} -e'4s/💩/👃/4' -e'5s/💩/👄/5' -e'1s/人/👑/'

unko.towerを用いない場合

unko.towerを使わない場合、以下のようにperlでそれに相当する処理をするのが楽。

(
  x=5; \
  eval echo {${x}..1} | \
    fmt -1 | \
    perl -snle '$l=" "x$_;$m="💩"x($n-$_);print $l."($m💩$m)"' -- -n=${x} \
) | \
    sed -e"s/(💩)/ 👑/" -e'3s/💩/👁/'{2,3} -e'4s/💩/👃/4' -e'5s/💩/👄/5'
$ (
>   x=5; \
>   eval echo {${x}..1} | \
>     fmt -1 | \
>     perl -snle '$l=" "x$_;$m="💩"x($n-$_);print $l."($m💩$m)"' -- -n=${x} \
> ) | \
>     sed -e"s/(💩)/ 👑/" -e'3s/💩/👁/'{2,3} -e'4s/💩/👃/4' -e'5s/💩/👄/5'
      👑
    (💩💩💩)
   (💩👁💩👁💩)
  (💩💩💩👃💩💩💩)
 (💩💩💩💩👄💩💩💩💩)

unko.towerの中・外にテキストを表示させる

unko.towerのウンコの中やその背景に任意の文字列を表示させるシェル芸。

イメージ的には大昔にあったメッセージカードみたいな感じだろうか。 いわばウンコのメッセージカード…!

unko.towerの中にテキストを差し込む

やってることは単純で、sedで正規表現を使って()の中の全角スペースにテキストを一文字づつ差し込んでるだけだ。

unko.tower 4 | sed -r ":a;s/(( *) /\1_/;ta" | eval sed -z -e'"s/_/"'{$(echo うんこの中にめっせぇじをいれるよ!こんな感じだよ|sed "s/./&,/g;s/,$//g")}'"/"'
# 読みやすく改行したバージョン
unko.tower 4 \
    | sed -r ":a;s/(( *) /\1_/;ta" \
    | eval sed -z -e'"s/_/"'{$(echo うんこの中にめっせぇじをいれるよ!こんな感じだよ|sed "s/./&,/g;s/,$//g")}'"/"'

応用で、テキストを流すような形でウンコの中で動かしてみる。

echo 我は関うん長!この青龍うん月刀の切れ味をみよ!|sed ':a;p;s/\(.\)\(.*\)/\2\1/;ba'|head -26|xargs -I@ bash -c 'unko.tower 3|sed -r ":a;s/(( *) /\1_/;ta"|eval sed -z -e$'\x27'"s/_/"$'\x27'{$(echo @|sed "s/./&,/g;s/,$//g")}$'\x27'"/"$'\x27' -e"s/_/!/g"'|textimg -s -al 4
# 読みやすく改行したバージョン
echo 我は関うん長!この青龍うん月刀の切れ味をみよ! \
    | sed ':a;p;s/\(.\)\(.*\)/\2\1/;ba' \
    | head -26 \
    | xargs -I@ bash -c '
        unko.tower 3 \
        | sed -r ":a;s/(( *) /\1_/;ta" \
        | eval sed -z -e$'\x27'"s/_/"$'\x27'{$(echo @|sed "s/./&,/g;s/,$//g")}$'\x27'"/"$'\x27' -e"s/_/!/g"
    ' \
    | textimg -s -al 4

1文字づつ出力するような表示をさせてみる。

echo うんこの中にめっせぇじを入れて想いを伝えようっ! | grep -o . | awk '{a=a$0;printf("%-24s\n",a)}' | sed 's/ /_/g' | xargs -I@ bash -c 'unko.tower 4|sed -r ":a;s/(( *) /\1_/;ta"|eval sed -z -e$'\x27'"s/_/"$'\x27'{$(echo @|sed "s/./&,/g;s/,$//g")}$'\x27'"/"$'\x27'' | textimg -s -al 5
# 読みやすく改行したバージョン
echo うんこの中にめっせぇじを入れて想いを伝えようっ! \
    | grep -o . \
    | awk '{a=a$0;printf("%-24s\n",a)}' \
    | sed 's/ /_/g' \
    | xargs -I@ bash -c '
        unko.tower 4 \
        | sed -r ":a;s/(( *) /\1_/;ta"|eval sed -z -e$'\x27'"s/_/"$'\x27'{$(echo @|sed "s/./&,/g;s/,$//g")}$'\x27'"/"$'\x27'' \
    | textimg -s -al 5

ちなみに、現行バージョンのunko_towerだと-sとか-mで普通にテキストを入れられる。 これが需要のある技術は進歩していくということの証明なのである(´・ω・`)。

$ unko.tower -m ウンコの中にテキストが入る。これが全人類の希望の象徴であるうんこタワーの新しい姿なのか!うんこ! 6
        人
      (ウンコ)
     (の中にテキ)
    (ストが入る。こ)
   (れが全人類の希望の)
  (象徴であるうんこタワー)
 (の新しい姿なのか!うんこ!)

unko.towerの背景にテキストを差し込む

応用で、ウンコのバックにテキストを差し込んでみる。

unko.tower 5|sed -r ':a;s/(( *) /\1_/;ta'|awk '{printf($0);for(i=length($0);i<=14;i++){printf(" ")};print ""}'|eval sed -z -e'"s/ /"'{$(echo それはうんこというにはあまりにも大きすぎた。大きく、分厚く、重くそして大雑把すぎた。それはまさにうん塊だった|sed 's/./&,/g;s/,$//g')}'"/"'
# 読みやすく改行したバージョン
unko.tower 5 \
    | sed -r ':a;s/(( *) /\1_/;ta' \
    | awk '{printf($0);for(i=length($0);i<=14;i++){printf(" ")};print ""}' \
    | eval sed -z -e'"s/ /"'{$(echo それはうんこというにはあまりにも大きすぎた。大きく、分厚く、重くそして大雑把すぎた。それはまさにうん塊だった | sed 's/./&,/g;s/,$//g')}'"/"'

さらに応用で、こちらもテキストを動かしてみる。

echo それはうんこというにはあまりにも大きすぎた。大きく、分厚く、重くそして大雑把すぎた。それはまさにうん塊だった。|sed ':a;p;s/\(.\)\(.*\)/\2\1/;ba'|head -56|xargs -I@ bash -c 'unko.tower 3|sed -r ":a;s/(( *) /\1_/;ta"|awk "{printf(\$0);for(i=length(\$0);i<=10;i++){printf(\" \")};print \"\"}"|eval sed -z -e$'\x27'"s/ /"$'\x27'{$(echo @|sed "s/./&,/g;s/,$//g")}$'\x27'"/"$'\x27''|textimg -s -al 4
# 読みやすく改行したバージョン
echo それはうんこというにはあまりにも大きすぎた。大きく、分厚く、重くそして大雑把すぎた。それはまさにうん塊だった。 \
    | sed ':a;p;s/\(.\)\(.*\)/\2\1/;ba' \
    | head -56 \
    | xargs -I@ bash -c '
        unko.tower 3 \
        | sed -r ":a;s/(( *) /\1_/;ta" \
        | awk "{printf(\$0);for(i=length(\$0);i<=10;i++){printf(\" \")};print \"\"}" \
        | eval sed -z -e$'\x27'"s/ /"$'\x27'{$(echo @|sed "s/./&,/g;s/,$//g")}$'\x27'"/"$'\x27'
    ' \
    |textimg -s -al 4

ネストしたecho-sdの吹き出しの色を変えるgifを生成する

echo-sdをネストさせて、かつ特定の吹き出しの枠だけ色を変えてみる。 ターミナルで文字や背景色の色を変える場合はエスケープシーケンスを使うのが楽なので、それで色々と対応する。

↓のコマンドでは、textimgに食わせてgif画像にしている。

seq -f 'echo 丸の内にゃんにゃんOL|eval "echo-sd -s|"{,,,,,} cat|(i=%g&&sed -r -e{${i},$((14-i))}"s/[^><]+/\x1b[3${i}m&\x1b[0m/g" -e"$((i+1)),$((13-i))s/^(.{$((i*2-1*2))})( *)(.)/\1\2\x1b[3${i}m\3\x1b[0m/" -e"$((i+1)),$((13-i))s/(.)( *)(.{"$((i*2-1*2))"})$/\x1b[3${i}m\1\x1b[0m\2\3/")' 6|pee tac cat|uniq|bash|sed 's/^/echo /;s/にゃん/$(lolcat -f --freq=1.0 <<<にゃん)/g'|bash|textimg -sal 13

トランプや麻雀牌の絵文字を使って遊ぶ

Unicodeに、トランプや麻雀牌の各絵柄が用意されてるので、それを使って遊んだりすることもできる。

$ shuf -n 14 -e {0..33}{,,,} | sort -n | xargs -I@ bash -c 'printf $(printf \\\\U1F0%02x @)'
🀀🀂🀄🀅🀆🀆🀇🀑🀒🀕🀜🀝🀞🀟
$ shuf -n 5 -e $(echo $(printf "printf $'\\\U1F0%02x'\n" {{161..174},{177..190},{193..206},{209..222}}|bash){,,,} $(printf "printf $'\\U1F0%02x'\n" 207|bash){,} | sed 's/ //g;s/\B/ /g') | tr -d '\n' && echo
🂹🃆🃍🃅🂡

縦読み・ななめ読みをgrepする

縦読みをgrepする

縦読みの場合。

rsコマンドとか使って縦横変換するのでいいんじゃないか? という気もするけど、awkとか使っても処理はできる。 なので、ここではawkを使う。

# awk使ってやる場合
awk -F '' '{for(i=1;i<=NF;i++){a[NR,i]=$i}}NF>p{p=NF}END{for(j=1;j<=p;j++){str=a[1,j];for(i=2;i<=NR;i++){str=str""a[i,j];}print str}}' file_path | cat -n | grep -i 文字列

# ebanさんに教えてもらった、もっと短いバージョン
seq $(awk '{n=length($0);if(m<n) m=n}END{print m}' file_path) | xargs -I@ awk '{a=a substr($0,@,1)}END{print a}' file_path | grep -n 文字列
$ cat a.txt
長い夢から覚めた気分だ・・・俺は気がつくとここにいた
門の前には2つの人影がある・・・1人は若い男だ
はっとした。見間違いだと思った・・・あの・・・もう1人の人物は・・・
俺は信じがたい光景を目の当たりにして少々混乱した
のうのうと生きてきた自分を初めて呪った・・・
嫁だ・・・これは・・・嫁の浮気現場だったのだ・・・俺は神を憎み、絶望した・・・
$
$ cat a.txt | awk -F '' '{for(i=1;i<=NF;i++){a[NR,i]=$i}}NF>p{p=NF}END{for(j=1;j<=p;j++){str=a[1,j];for(i=2;i<=NR;i++){str=str""a[i,j];}print str}}' | cat -n | grep -i 長門
     1  長門は俺の嫁
$
$ seq $(awk '{n=length($0);if(m<n) m=n}END{print m}' a.txt) | xargs -I@ awk '{a=a substr($0,@,1)}END{print a}' a.txt | grep -n 長門
1:長門は俺の嫁

ななめ読みをgrepする

縦読みじゃなくてななめ読みの場合。

seq $(awk '{n=length($0);if(m<n) m=n}END{print m}' file_path)|xargs -I@ awk '{s=@-1;a=a substr($0,s+NR,1)}END{print a}' file_path | grep -n 文字列
$ cat a.txt
ななめ読みとは、時間を省くためなどに文章を要点以外は飛ばして読むことである。
あなたも新聞や小説を読む時にしっかり読まずに斜め読みをしたことがあるだろう。
なおめだち易い文章だけ読んで目立ちにくい文章を飛ばして読む方法もある。
やはり読書する時はななめ読みすると早く読めるのでオススメである。
やっぱりみんなもどんどん斜め読みをすべきである。
$
$ seq $(awk '{n=length($0);if(m<n) m=n}END{print m}' a.txt)|xargs -I@ awk '{s=@-1;a=a substr($0,s+NR,1)}END{print a}' a.txt
ななめ読み
なただ書ん
めもちすな
読新易るも
み聞い時ど
とや文はん
は小章など
、説だなん
時をけめ斜
間読読読め
をむんみ読
省時ですみ
くに目るを
たし立とす
めっち早べ
なかにくき
どりく読で
に読いめあ
文ま文るる
章ず章の。
をにをで
要斜飛オ
点めばス
以読しス
外みてメ
はを読で
飛しむあ
ばた方る
しこ法。
てとも
読があ
むある
こる。
とだ
でろ
あう
る。
。
$
$  seq $(awk '{n=length($0);if(m<n) m=n}END{print m}' a.txt)|xargs -I@ awk '{s=@-1;a=a substr($0,s+NR,1)}END{print a}' a.txt  | grep -n ななめ
1:ななめ読み

漢数字ソートをする

コマンドで漢数字ソートをする場合。 漢数字は文字コード上順番が揃っていないので、普通にsortに渡すと数字としてsortはされない。

なので、joinで漢数字順になっているものを組み合わせてやることで対処したりする。

# joinに渡しているプロセス置換の1個め(`三三七上一八六九四下二上五`)をsort
join -2 2 -a1 \
    <(echo 三三七上一八六九四下二上五|grep -o .|sort) \
    <(echo 一二三四五六七八九十上中下|grep -o .|nl|sort -k2) \
|sort -k2n|awk '{print $1}'

# ebanさんから教えてもらったもの。rubyの場合`zen_to_i`を使うことで対応できるらしい
echo 二五下三九七八中十六四上一 | ruby -rzen_to_i -nle 'puts $_.chars.sort_by{|x|x.zen_to_i.to_i}*""'
$ join -2 2 -a1 \
>     <(echo 三三七上一八六九四下二上五|grep -o .|sort) \
>     <(echo 一二三四五六七八九十上中下|grep -o .|nl|sort -k2) \
> |sort -k2n|awk '{print $1}'
一
二
三
三
四
五
六
七
八
九
上
上
下
$
$ echo 二五下三九七八中十六四上一 | ruby -rzen_to_i -nle 'puts $_.chars.sort_by{|x|x.zen_to_i.to_i}*""' | grep -o .
下
中
上
一
二
三
四
五
六
七
八
九
十

アラビア数字を漢数字に変換する

アラビア数字から漢数字に変換して、かつとかといった単位も付ける場合。

echo 123456789 | sed 'y/0123456789/〇一二三四五六七八九/' | grep -o . | tac | paste - <(echo {十,百,千,万,十,百,千,億} | fmt -1 | cat <(echo) -) | grep -vE ^$'\t' | tac | sed -zr 's/(\t|\n)//g'| perl -lpe 's/一(?!($|万|億))//g;s/〇(?!$)//g'
$ echo 123456789 | sed 'y/0123456789/〇一二三四五六七八九/' | grep -o . | tac | paste - <(echo {十,百,千,万,十,百,千,億} | fmt -1 | cat <(echo) -) | grep -vE ^$'\t' | tac | sed -zr 's/(\t|\n)//g'| perl -lpe 's/一(?!($|万|億))//g;s/〇(?!$)//g'
一億二千三百四十五万六千七百八十九

シーザー暗号を作る

ROT13とか色々呼び方あるけど、シーザー暗号を作るシェル芸。

# trとかで処理する場合
echo King Unko ha Shellgeibot No Mascot dayo | tr $(printf %9s | tr ' ' '.' | tac)\a-z a-za-z | tr $(printf %9s | tr ' ' '.' | tac)\A-Z A-ZA-Z

# ebanさんに教えてもらったやつ
echo King Unko ha Shellgeibot No Mascot dayo | tr "$(printf %s {a..z} | sed -E 's/^(.{9})(.*)/\2\1/;s/.*/&\U&/')" a-zA-Z
$ echo King Unko ha Shellgeibot No Mascot dayo | tr $(printf %9s | tr ' ' '.' | tac)\a-z a-za-z | tr $(printf %9s | tr ' ' '.' | tac)\A-Z A-ZA-Z
Trwp Dwtx qj Bqnuupnrkxc Wx Vjblxc mjhx
$
$ echo King Unko ha Shellgeibot No Mascot dayo | tr "$(printf %s {a..z} | sed -E 's/^(.{9})(.*)/\2\1/;s/.*/&\U&/')" a-zA-Z
Bzex Lebf yr Jyvccxvzsfk Ef Drjtfk urpf

文字列を使って形をつくる

Nグラムを生成する

echo 響け!ユーフォニアム|sed -r ':a;p;s/(.)(.*)/\2\1/;ba'|head
$ echo 響け!ユーフォニアム|sed -r ':a;p;s/(.)(.*)/\2\1/;ba'|head
響け!ユーフォニアム
け!ユーフォニアム響
!ユーフォニアム響け
ユーフォニアム響け!
ーフォニアム響け!ユ
フォニアム響け!ユー
ォニアム響け!ユーフ
ニアム響け!ユーフォ
アム響け!ユーフォニ
ム響け!ユーフォニア

Nグラムを床屋のサインポール状に動かしてみる

# ターミナル上で再生する場合
echo 響け!ユーフォニアム|sed ':a;p;s/\(.\)\(.*\)/\2\1/;ba'|xargs -I@ bash -c 'clear;echo @|sed -ne"p;s/\(.\)\(.*\)/\\2\\1/;#"{0..9}|grep --color=always 響;sleep 0.1'

# textimgを利用する場合
echo 響け!ユーフォニアム|sed ':a;p;s/\(.\)\(.*\)/\2\1/;ba'|xargs -I@ bash -c 'echo @|sed -ne"p;s/\(.\)\(.*\)/\\2\\1/;#"{0..9}|grep --color=always 響' | head -100 | textimg -sal 10

階段状に出力する

echo あいうえお | grep -o . | awk 'a=$0=a$0'
$ echo あいうえお | grep -o . | awk 'a=$0=a$0'
あ
あい
あいう
あいうえ
あいうえお

ピラミッド風に

最後の文字列を基準に回文を作って、それをピラミッド風に出力する。

echo あいうえお| grep -o . | tac | awk '{a=a?$0a$0:$0;print a}' | xargs -I@ bash -c 'printf "%*s\n" $(( (27 + $(printf @ | wc -c)) / 2 )) @' | sed 's/   / /g'
$ echo あいうえお| grep -o . | tac | awk '{a=a?$0a$0:$0;print a}' | xargs -I@ bash -c 'printf "%*s\n" $(( (27 + $(printf @ | wc -c)) / 2 )) @' | sed 's/   / /g'
    お
   えおえ
  うえおえう
 いうえおえうい
あいうえおえういあ

砂時計っぽく

ピラミッド風に出力しているものを利用して、砂時計っぽい形に加工。

echo あいうえお|grep -o .|tac|awk '{a=a?$0a$0:$0;$0=a;printf("%9s\n",a)}'|tac|tee >(tac)|sed 's/  / /g;1i.' | uniq
echo あいうえお|grep -o .|awk '{a=a?a$0:$0;"echo "a"|rev|sed s/^.//"|getline b;printf("%9s\n",a b)}'|tac|tee >(tac)|sed 's/  / /g'|uniq
$ echo あいうえお|grep -o .|tac|awk '{a=a?$0a$0:$0;$0=a;printf("%9s\n",a)}'|tac|tee >(tac)|sed 's/  / /g;1i.' | uniq
.
あいうえおえういあ
 いうえおえうい
  うえおえう
   えおえ
    お
   えおえ
  うえおえう
 いうえおえうい
あいうえおえういあ
$
$ echo あいうえお|grep -o .|awk '{a=a?a$0:$0;"echo "a"|rev|sed s/^.//"|getline b;printf("%9s\n",a b)}'|tac|tee >(tac)|sed 's/  / /g'|uniq
あいうえおえういあ
 あいうえういあ
  あいういあ
   あいあ
    あ
   あいあ
  あいういあ
 あいうえういあ
あいうえおえういあ

文字列をひし形状に出力する

例えばecho 焼き肉が食べたいから↓のような出力を得る場合。

   焼
  焼肉が
 焼肉が食べ
焼肉が食べたい
 が食べたい
  べたい
   い
echo 焼肉が食べたい | \
   jq -Rr 'length as$l|range(length)as$r|. as$i|" "*($l-$r-1)+$i[:$r]+$i[$r:($r*2)+1]'| # jqで大まかな処理をする \
   awk 'NR==1{print "echo " $$0}NR>1{print "echo " $$0"|sed -es/./ /{1.."NR-1"}"}' | # awkで余計な文字を削除するコマンドを生成 \
   bash | sed -r 's/^.{3}//g' # 実行と余計な行頭の空白を削除
$ echo 焼肉が食べたい | \
>    jq -Rr 'length as$l|range(length)as$r|. as$i|" "*($l-$r-1)+$i[:$r]+$i[$r:($r*2)+1]'| # jqで大まかな処理をする \
>    awk 'NR==1{print "echo " $$0}NR>1{print "echo " $$0"|sed -es/./ /{1.."NR-1"}"}' | # awkで余計な文字を削除するコマンドを生成 \
>    bash | sed -r 's/^.{3}//g' # 実行と余計な行頭の空白を削除
   焼
  焼肉が
 焼肉が食べ
焼肉が食べたい
 が食べたい
  べたい
   い

中心から放射状にひし形を形成していく

亜種。中心から外に向けて文字を並べていく場合。

echo あいうえお|grep -o .|tac|awk '{print "echo $(echo "a")"$0"$(echo "a"|rev)";a=a$0}'|bash|xargs -I@ bash -c 'printf "%*s\n" $(( (27 + $(printf @ | wc -c)) / 2 )) @'|sed 's/   / /g'|pee cat tac|cat|sed 5d
$ echo あいうえお|grep -o .|tac|awk '{print "echo $(echo "a")"$0"$(echo "a"|rev)";a=a$0}'|bash|xargs -I@ bash -c 'printf "%*s\n" $(( (27 + $(printf @ | wc -c)) / 2 )) @'|sed 's/   / /g'|pee cat tac|cat|sed 5d
    お
   おえお
  おえうえお
 おえういうえお
おえういあいうえお
 おえういうえお
  おえうえお
   おえお
    お

真ん中にひし形状の空白を作る

ひし形状に出力する処理の逆バージョン。 こちらのほうが短く書ける。

echo 焼き肉が食べたい | \
  sed -r ':a;p;s/./&  /4;s/(^.|.$)//g;ba' | \
  head -4 | tee >(cat) >(sleep 0.1;tac|rev) >/dev/null | \
  cat
$ echo 焼き肉が食べたい | \
>   sed -r ':a;p;s/./&  /4;s/(^.|.$)//g;ba' | \
>   head -4 | tee >(cat) >(sleep 0.1;tac|rev) >/dev/null | \
>   cat
焼き肉が食べたい
き肉が  食べた
肉が    食べ
が      食
食      が
べ食    が肉
たべ食  が肉き
いたべ食が肉き焼

文字列を線とする四角形を作る

さらに応用で、空白を囲む形で文字列が四角形の線となるもの。

echo 焼き肉が食べたい! | \
   sed -r 's/(.)(.*)/\1\2\1/g;:a;p;s/./&  /5;s/(^.|.$)//g;/^ /!ba;$d'| \
   awk 'NR==1{print}NR>1{print|"rev"}' | \
   tee >(cat) >(tac|rev) >/dev/null | \
   cat | perl -C -pe 'use utf8;s/((?<!^).(?!$))/ /g if 2..9'
$ echo 焼き肉が食べたい! | \
>    sed -r 's/(.)(.*)/\1\2\1/g;:a;p;s/./&  /5;s/(^.|.$)//g;/^ /!ba;$d'| \
>    awk 'NR==1{print}NR>1{print|"rev"}' | \
>    tee >(cat) >(tac|rev) >/dev/null | \
>    cat | perl -C -pe 'use utf8;s/((?<!^).(?!$))/ /g if 2..9'
焼き肉が食べたい!焼
!        き
い        肉
た        が
べ        食
食        べ
が        た
肉        い
き        !
焼!いたべ食が肉き焼

テキストの周りで文字列を回転させる

さらにさらに応用して、文字列を動かして中の空白にもテキストを入れたもの。

echo マジカルうんこ|sed -r ':a;p;s/(.)(.*)/\2\1/;ba'|head -7|xargs -I@ bash -c 'echo @|sed -r "s/(.)(.*)/\1\2\1/g;:a;p;s/./&  /4;s/(^.|.\$)//g;/^ /!ba;\$d"|sed -r "1!s/.+/echo &|rev/ge"|perl -C -pe '\''use utf8;s/((?<!^).(?!$))/ /g if 2..n'\''|pee cat "tac|rev"'|sed -f <(echo マジカルうんこ|grep -o .|cat -n|awk '{print "s/"$2"/\\x1b[3"$1"m&\\x1b[0m/g"}')|eval sed -z -e'"s/ /"'{$(echo 君は覚えているだろうか?まだうんこが動いてなかったあの頃のことを・・・・{,,,,,,}|sed "s/ //g;s/./&,/g;s/,$//g")}'"/"'|textimg -al8 -s

仕事・作業等で使ったやつ

個人的に仕事とか作業のときに使ってるワンライナーを抜粋しておく。

ブレース展開を用いたバックアップファイルの作成

シェル芸とも呼べないようななにか。 これは普通に使ってる人が大半だと思う。

普通に、ブレース展開で拡張子のとこに文字追加してるだけ。

cp file.txt{,.bk}
$ # echoが実行されるより前にブレース展開が展開されるため
$ # cpで同じことをした場合、出力結果と同じコマンドが実行されることになる
$ echo cp file.txt{,.bk}
cp file.txt file.txt.bk

今日の日付のディレクトリ、ファイルを作成する

これもシェル芸とは呼べないような超カンタンなTips。 普通に使ってる人が多いと思う。

コマンド置換を利用して作成するファイル名を生成し、それを使ってコマンドを実行させるやり方。

mkdir $(date +%Y%m%d)
touch $(date +%Y%m%d).txt

雑なサンプルCSVの生成

雑にサンプル用CSVを生成する場合の処理方法。

どの列もテキトーに文字列でいいのなら、ブレース展開で適当に生成してxargsで列数ごとに分割してやる。 基本的にはこの方式でだいたい対処できると思う。

# csvの場合
echo {a..z}{01..05} | xargs -n 5 | tr \  ,

# tsvの場合
echo {a..z}{01..05} | xargs -n 5 | tr \  $'\t'

列の値に制限があるのであれば、ブレース展開で処理しているところを書き換えてやれば対応できるだろう。

数字を単位付き(万億兆京垓)にして読みやすくする

桁数の多い数字だと、カンマがついててもまだパッと読めなかったので、日本語で単位を付けて読みやすくする処理。

echo 1213141516170819 | rev | sed -r -e's/[0-9]{4}/&,/g' -e's/,/'{万,億,兆,京,垓}'/1' -e's/0+([^0-9])/\1/g;s/([^0-9])([^0-9])/\2/g;s/[^0-9]$//g' -e's/([0-9]{3})([0-9])/\1,\2/g' | rev
$ echo 1213141516170819 | rev | sed -r -e's/[0-9]{4}/&,/g' -e's/,/'{万,億,兆,京,垓}'/1' -e's/0+([^0-9])/\1/g;s/([^0-9])([^0-9])/\2/g;s/[^0-9]$//g' -e's/([0-9]{3})([0-9])/\1,\2/g' | rev
1,213兆1,415億1,617万819

scriptコマンドで記録するターミナルログにタイムスタンプを付与する

WindowsでTeratermを使ってる人なら、Teratermログみたいな形式(行の先頭にタイムスタンプが付いてる形式)でターミナルログを記録する方法 と考えてもらればいいと思う。 通常、多くのUNIX系OS(一般的なLinuxディストリビューションやMacとか)だとscriptコマンドというターミナルログを記録するコマンドがあるのだが、それで行頭にタイムスタンプを付与する方法。

これはプロセス置換 (>(command)とか<(command)と記述することで、ファイルを指定するように実行コマンドに渡す機能) を利用することで、比較的容易に実現可能だ。 以下、実行例。 プロセス置換でターミナルログを送るコマンドはawkを使っている(楽なので)。

script -fq >(awk '{print strftime("%F %T ") $0}{fflush() }'>> PATH)

(応用例)コマンド実行とセットで使用する

応用で、コマンドの実行と同時にターミナルログを取得するようにもできる。

なおBSDとLinuxの違いなのか知らないが、scriptコマンドの書き方がMacとLinuxで違うようなので注意。

Linuxでのコマンド

script -fq -c "コマンド" >(awk '{print strftime("%F %T ") $0}{fflush() }'>> PATH)

Mac(BSD系)でのコマンド

script -Fq >(awk '{print strftime("%F %T ") $0}{fflush() }'>> PATH) 'コマンド("などで囲まない)'

(応用例)ssh接続と同時にターミナルログをタイムスタンプ付きで取得

コマンド実行と同時にターミナルログを取る方法を利用すれば、ssh接続時のターミナルログをタイムスタンプ付きで取得できる。

Linuxでのコマンド

script -fq -c "ssh user@hostname" >(awk '{print strftime("%F %T ") $0}{fflush() }'>> PATH)

Mac(BSD系)でのコマンド

script -Fq >(awk '{print strftime("%F %T ") $0}{fflush() }'>> PATH) "ssh user@hostname"

(応用例)pingの行頭にタイムスタンプを付与する

scriptコマンドのログにタイムスタンプをつけるのと同じように、pingの行頭にタイムスタンプをつけることも可能だ。

むしろこちらのほうがプロセス置換とかを使わずにawkだけで実現可能なので楽かも。

ping 8.8.8.8 | awk '{print strftime("%F %T ") $0}{fflush() }'
$ ping 8.8.8.8 | awk '{print strftime("%F %T ") $0}{fflush() }'
2020-05-02 10:49:48 PING 8.8.8.8 (8.8.8.8): 56 data bytes
2020-05-02 10:49:48 64 bytes from 8.8.8.8: icmp_seq=0 ttl=55 time=265.068 ms
2020-05-02 10:49:49 64 bytes from 8.8.8.8: icmp_seq=1 ttl=55 time=67.235 ms
2020-05-02 10:49:50 64 bytes from 8.8.8.8: icmp_seq=2 ttl=55 time=127.855 ms
2020-05-02 10:49:51 64 bytes from 8.8.8.8: icmp_seq=3 ttl=55 time=59.600 ms
2020-05-02 10:49:52 64 bytes from 8.8.8.8: icmp_seq=4 ttl=55 time=16.395 ms
2020-05-02 10:49:53 64 bytes from 8.8.8.8: icmp_seq=5 ttl=55 time=26.725 ms

ちなみに、moreutilsにはtsコマンドというタイムスタンプを付与するコマンドがある。 awkやperlなどで処理するのがめんどくさかったらそちらを使う方法もありかもしれない。

ssh接続先にローカルのbashrc・vimrcを、ファイルを作らずにリモートのシェルで使用する

個人的にもよく使ってる方法。 bashの場合、シェル起動時に--rcfileオプションでbashrcファイルを指定できるのだが、そこにプロセス置換でローカルのbashrcファイルの内容を渡すことで実現する。

このとき、そのまま渡すと改行やエスケープ、クォーテーションが悪さをするのでbase64にしてssh接続先に渡すようにする。

Macでのコマンド

ssh -t user@host '
    bash --rcfile <(
        echo -e ' $(cat <(echo "function lvim() { vim -u <(echo "$(cat ~/.vimrc|base64)"|base64 -d) $@ ; }") \
                        ~/dotfiles/{.bashrc,sh_function,sh_alias,bash_prompt} \
                        <(echo -e alias vim=lvim) | \
                        base64
                   ) ' \
        |base64 -d)'

Linuxでのコマンド

Linuxでバンドルされてるbase64の場合、-w0を付けないと改行が入ってしまう。

ssh -t user@host '
    bash --rcfile <(
        echo -e ' $(cat <(echo "function lvim() { vim -u <(echo "$(cat ~/.vimrc|base64)"|base64 -d) $@ ; }") \
                        ~/dotfiles/{.bashrc,sh_function,sh_alias,bash_prompt} \
                        <(echo -e alias vim=lvim) | \
                        base64 -w0
                   ) ' \
        |base64 -d)'

パラレルにpingを実行して一気にセグメント内の疎通確認を行う

pingを実行する際、xargsで並列にプロセスを立ち上げることで一気に複数ホストへのpingをして、短時間で一気に疎通確認を行える。 普通に直列でpingをするよりもNWに負荷がかかるけど、流石に最近の環境であればそこまで大きい影響は出ないだろうと思う。

# 192.168.0.1-254に一気にpingをして疎通できたIPアドレスだけ抽出
echo 192.168.0.{1..254} | xargs -P254 -n1 ping -s1 -c1 -w1 | grep ttl | sort -V -k4

なお、↑の例だとGNU sortのVersion Sortを使ってるので、Macだと動作しない可能性がある。 Macの場合は-Vオプションを消して実行したほうがいいだろう。

ちょっとした小ネタ

親和性の高そうなもので、ちょっとした小ネタについて。

iTerm2での画像表示

iTerm2では独自仕様の機能でターミナル内で画像表示が行える。 この機能を使ったスクリプトのサンプルが公式で用意されているので、これを参考にカスタマイズもできる。 (自分の場合はssh先の画像を表示するためにshell functionにしている)

OSCエスケープシーケンスでのターミナル表示設定(文字色・背景色・プロファイルなど)

ターミナルによって書き方が変わってしまうが、OSCエスケープシーケンスを利用するとターミナルの背景色や文字色、画像などを定義したプロファイルの切り替えが行える。 iTerm2の場合はプロファイルの切り替えができるので、ssh先ごとにプロファイルを切り替える(文字色や背景画像を切り替える)といった使い方もできる。

iTerm2の場合

printf "\E]50;SetProfile=プロファイル名\a" # 指定したプロファイルに変更する
printf "\E]1337;SetColors=bg=E\a\E]1337;SetColors=fg=ccc\a" # 文字色・背景色を変更する(RGBを0〜fで指定)

Gnome Terminal等の場合

Gnome Terminal以外でも動作すると思うけど、特に保証はないので試してみないと分からない。 Terminatorでは動くことを確認している。

echo -ne '\e]10;#000000\a' # 文字色を変更
echo -ne '\e]11;#ffffff\a' # 背景色を変更

echo -ne '\e]10;#ffffff\a\e]11;#000000\a'文字色を白、背景色を黒に
echo -ne '\e]10;#ffffff\a\e]11;#300000\a'文字色を白、背景色を赤に
echo -ne '\e]10;#ffffff\a\e]11;#003000\a'文字色を白、背景色を緑に
echo -ne '\e]10;#ffffff\a\e]11;#000030\a'文字色を白、背景色を青に
echo -ne '\e]10;#000000\a\e]11;#ffffff\a'文字色を黒、背景色を白に