深酒とお昼寝で忘れる

深酒とお昼寝で忘れる

素面でも意図したことを忘れがちなしらふいとさんは、忘れる前に何かしら書き残せたらとても満足のようです

各行に書かれている数字の総和を出力する

分かりにくいタイトルですが、要は下記のようなファイル(または grepsed などの出力でも良いです)の総和を出力するにはどうしたら良いかな、ということです。

1
100
39
:
153

sed で全てを足しあわせる数式に整形して bc に渡しても良いのですが、awk を使ったこの方法がスマートです。

awk '{s+=$1} END {print s}'

ここ で知りました。

複数のスペースを一つに置換できますか(ただし引用符の中は除く)

以前 zsh で、失敗したコマンドはヒストリファイルに保存しない設定をしました(付随して、スペースで始まるコマンドは履歴に残さない、コマンド内の複数のスペースは一つに置換する、といった設定も自前で行ないました)が、使っていくうちにいくつか改善できる点が分かってきました。今回はそのうち、複数のスペースを一つに置換する設定について紹介します。

以前の設定では、複数のスペースを一つに置換する zsh のオプションである hist_reduce_blanks 相当の機能を実現するためにコマンドの文字列に対して tr -s ' ' を実行していました。大抵はこれで問題ないのですが、うまくいかない場合もあります。例えば、

grep    '    something    '

というコマンドは、

grep '    something    '

のように履歴に保存されてほしいのですが、

grep ' something '

として保存されます。grep' の間の複数のスペースは一つに置換したいけれども引用符('")の中についてはそのままにしたいわけです。

ということで、設定を変更します。なるべくシンプルなワンライナーで実現したいと思ったのですが、自分の正規表現力では無理なのでちょこちょこと検索すること数日間……。最終的に、該当個所は下記のようになりました。

local cmd_reduce_blanks
if [[ ${_LASTCMD} =~ \" ]]; then
  cmd_reduce_blanks=$(echo ${_LASTCMD} \
    | perl -pe 's/ +(?=(([^"]*"){2})*[^"]*$)/ /g')
elif [[ ${_LASTCMD} =~ \' ]]; then
  cmd_reduce_blanks=$(echo ${_LASTCMD} \
    | perl -pe "s/ +(?=(([^']*'){2})*[^']*$)/ /g")
else
  cmd_reduce_blanks=$(echo ${_LASTCMD} | tr -s ' ')
fi

この手の処理で活躍する sedawk ではなく、Stack Overflow の回答 を参考にして Perl に頼ることになりました。" の中以外の複数のスペースを一つに置換するコマンドは

perl -pe 's/ +(?=(([^"]*"){2})*[^"]*$)/ /g'

となります(' の中以外を対象とする場合は "' を入れ替えてください)。この正規表現の具体的な説明は こちらの正規表現テスタ をご覧ください。コマンドに "' の両方を使うことはまれだと思うので、どちらか一方の引用符の中かどうかを判定するロジックになっています。

上記のコードでは _LASTCMD という変数にコマンドの文字列が保存されており(参照:以前の記事)、この文字列内の複数のスペースを一つに置換して cmd_reduce_blanks という変数に格納しています。ちなみに "' の両方を使うことはまれと書きましたが、' を引用符としてではなくアポストロフィとして " の引用符の中で使うことはあり得るかもしれません。例えば下記のようなコマンドです。

git    commit    -m    "Thank    God    it's    Friday"

このような場合でも正しく対応して

git commit -m "Thank    God    it's    Friday"

と履歴に保存するため、if 文はコマンドが " を含む場合を ' を含む場合よりも優先しています。いかがでしょうか。いやーしかし、正規表現、覚えられませんねー。

Mac (OS X El Capitan) で /home/$USER を /Users/$USER へのシンボリックリンクにする

あまり需要はない気がしますが記録しておきます。普通にシンボリックリンクを作ろうとすると、

$ cd /home
$ sudo ln -s /Users/$USER
ln: ./$USER: Operation not supported

上記のように怒られてしまいますが、/etc/auto_master ファイルの

/home    auto_home    -nobrowse,hidefromfinder

という行をコメントアウトしてから sudo automount -cv すると /home がアンマウントされるので、無事シンボリックリンクが作成できるようになります。

こちら でみつけました。