runo のすべての投稿

bash trap使うサンプル

trap中

#!/bin/bash -e

echo begin
trap 'echo trap exit' EXIT

echo processing
#sleep 3 # ターミナルでcontrol+C
#exit 1 # スクリプトをexit
#kill $$ # 自分のpidをkill
#false # -e オプション使用中に1の返り値

trap - EXIT
echo end

出力:

begin
processing
trap exit

trap解除後

#!/bin/bash -e

echo begin
trap 'echo trap exit' EXIT

echo processing

trap - EXIT

#sleep 3 # ターミナルでcontrol+C
#exit 1 # スクリプトをexit
#kill $$ # 自分のpidをkill
#false # -e オプション使用中に1の返り値

echo end

出力:

begin
processing

bash -e オプション

エラーコード(0以外のステータス)が発生した時にスクリプトを中断してくれる -e オプション。
中断しないケースを調べた。

中断しないケース

  • whileとuntilの直後のコマンドの場合
  • ifに使われている条件コマンドの場合
  • || や && リストに実行されるコマンドの場合、ただし最後のコマンドは除く
  • パイプラインの中のコマンドの場合、ただし最後のコマンドは除く
  • コマンドの結果を ! で反転している場合
  • サブシェルでエラーが発生したけど、その環境では-eを設定していない場合

エラーにたいするtrapが設定されている場合は、終わる前に実行される。

一部中断したくない場合の手段

||でコマンドを終わらせる

失敗した場合の処理又はtrueを追加する。
失敗コマンドのエラーコードは消えてしまう。

#!/bin/bash -e

false || true
echo $?
false || echo failed
echo $?
echo end

出力:

0
failed
0
end

&& trueでコマンドを終わらせる

何もしない && true で終わらせる。
失敗コマンドのエラーコードは取れる。

#!/bin/bash -e

false && true
echo $?
echo end

出力:

1
end

一時的に-eオプションを解除する

#!/bin/bash -e

set +e
false
set -e
echo end

出力:

end

参照

Bash Reference Manual (The Set Builtin) より引用:

Exit immediately if a pipeline (see Pipelines), which may consist of a single simple command (see Simple Commands), a list (see Lists), or a compound command (see Compound Commands) returns a non-zero status. The shell does not exit if the command that fails is part of the command list immediately following a while or until keyword, part of the test in an if statement, part of any command executed in a && or || list except the command following the final && or ||, any command in a pipeline but the last, or if the command’s return status is being inverted with !. If a compound command other than a subshell returns a non-zero status because a command failed while -e was being ignored, the shell does not exit. A trap on ERR, if set, is executed before the shell exits.

This option applies to the shell environment and each subshell environment separately (see Command Execution Environment), and may cause subshells to exit before executing all the commands in the subshell.

If a compound command or shell function executes in a context where -e is being ignored, none of the commands executed within the compound command or function body will be affected by the -e setting, even if -e is set and a command returns a failure status. If a compound command or shell function sets -e while executing in a context where -e is ignored, that setting will not have any effect until the compound command or the command containing the function call completes.

git でコミットの差分を適用

任意コミットの差分を適用

git cherry-pick --no-commit <commit1> #<commit2>...

オプション --no-commit(又は -n)を指定して任意コミットをチェリーピックすると、差分だけを適用できる。
(指定しないとコミットのコピーが現在のブランチにコミットされる)

例:


git cherry-pick --no-commit b61ae28116cfe5c4cc8bcc027e489fe40a5d1bff

マニュアルの説明:


git help cherry-pick
#...
       -n, --no-commit
           Usually the command automatically creates a sequence of commits.
           This flag applies the changes necessary to cherry-pick each named
           commit to your working tree and the index, without making any
           commit. In addition, when this option is used, your index does not
           have to match the HEAD commit. The cherry-pick is done against the
           beginning state of your index.

           This is useful when cherry-picking more than one commits' effect to
           your index in a row.

任意コミットのパッチの作成と適用

git diff <basecommit> <modifiedcommit> > patch.diff

git diff で差分のパッチを作成できる。
差分に入るファイルパスは、レポジトリのルートが基準になる。

patch -p0 < patch.diff

パッチファイルはレポジトリのルートで -p0 (=ファイルパスをそのまま守る)で適用すれば良い。

macOS でポップアップの選択肢をタブのキーで操作

設定

システム環境設定/キーボードショートカット タブにて、
フルキーボードアクセス の部分で すべてのコントロール を選択する。

操作方法

  • ポップアップやダイアログが出たら、タブでフォーカス(青い枠)を移動して、選択を決定する場合はスペースを使う。
  • デフォルト(下地が青)の項目で決定するときは、returnキーが使える。

Mac ターミナルのカスタマイズ

bash

設定ファイル:.bash_profile

alias ls='ls -G'
alias l='ls -la'

emacs

設定ファイル:.emacs

(custom-set-variables
  ;; custom-set-variables was added by Custom -- don't edit or cut/paste it!
  ;; Your init file should contain only one such instance.
 '(case-fold-search t)
 '(global-font-lock-mode t nil (font-lock))
 '(show-paren-mode t nil (paren))
 '(transient-mark-mode t))
(custom-set-faces
  ;; custom-set-faces was added by Custom -- don't edit or cut/paste it!
  ;; Your init file should contain only one such instance.
 )

(setq make-backup-files nil)
(column-number-mode t)
(line-number-mode t)

Ubuntu 16.04 に autofs を入れる

特定のディレクトリーにアクセスした時に、自動的にデバイス(USBポータブルHDD等)をマウントする。

インストール


sudo apt-get install autofs

設定

/etc/auto.master を編集する。

設定例

次の行を/etc/auto.masterの最後に追加。

/-      /etc/auto.runodrive
  • 外部ファイル /etc/auto.runodrive に指定された各ディレクトリーを自動マウントするようにする。

/etc/auto.runodriveにデバイスの設定。

/media/runodrive        -fstype=exfat,rw,exec,auto,relatime,noatime,iocharset=utf8,user,umask=111,dmask=000             UUID=57F0-5FB5
  • デバイスのUUIDを知るには sudo blkid

再起動


sudo service autofs restart

ViewControllerを別のViewControllerの任意ビューにはめ込む処理

public extension UIView {

    public func fillSuperviewWithConstaints() {

        let constraints = NSLayoutConstraint.constraints(fillingSuperviewOf: self)

        if #available(iOS 8, *) {
            NSLayoutConstraint.activate(constraints)
        } else {
            if let superview = superview {
                superview.addConstraints(constraints)
            }
        }
    }

}

public extension NSLayoutConstraint {

    public static func constraints(fillingSuperviewOf view: UIView) -> [NSLayoutConstraint] {
        guard let superview = view.superview else {
            return []
        }

        return [NSLayoutConstraint(item: view, attribute: .top, relatedBy: .equal, toItem: superview, attribute: .top, multiplier: 1.0, constant: 0.0),
                NSLayoutConstraint(item: view, attribute: .bottom, relatedBy: .equal, toItem: superview, attribute: .bottom, multiplier: 1.0, constant: 0.0),
                NSLayoutConstraint(item: view, attribute: .leading, relatedBy: .equal, toItem: superview, attribute: .leading, multiplier: 1.0, constant: 0.0),
                NSLayoutConstraint(item: view, attribute: .trailing, relatedBy: .equal, toItem: superview, attribute: .trailing, multiplier: 1.0, constant: 0.0),
        ]
    }

}

public extension UIViewController {

    public func addChildViewController(_ childViewController: UIViewController, filling parentView: UIView, withContraints: Bool) {

        addChildViewController(childViewController)
        childViewController.didMove(toParentViewController: self)

        if let subView = childViewController.view {
            parentView.addSubview(subView)

            if withContraints {
                subView.translatesAutoresizingMaskIntoConstraints = false
                subView.fillSuperviewWithConstaints()
            } else {
                subView.frame = parentView.bounds
            }
        }
    }

}

Protocol and Value Oriented Programming in UIKit Apps

WWDC2016で、Swiftのstruct、protocol、enumの有効な使い方について紹介するセッションがあった。

Protocol and Value Oriented Programming in UIKit Apps (WWDC 2016 – Session 419)

そのセッションで使われたサンプルコードがこちら。

LucidDreams: Protocol and Value Oriented Programming Sample Code

とても興味深くて、勉強になると思ったが、まだマスターできていない。

Ubuntu 16.04 に Transmission daemon を入れる

インストール


sudo apt-get install transmission-daemon

設定

設定ファイルは /etc/transmission-daemon/settings.json

デーモンが停止(再起動)されるときに、設定ファイルが起動中の設定で上書きされる。
そのためデーモンを一旦停止してから編集する。


sudo service transmission-daemon stop

RPCと基本的な設定

RPCさえ利用可能にすれば、 他の重要な設定はウェブから変更できる。
次の設定を/etc/transmission-daemon/settings.json側で行う。

    "rpc-password": "password",
    "rpc-username": "admin",
    "rpc-port": 9091,
    "rpc-whitelist": "127.0.0.1",
    "rpc-whitelist-enabled": false,
    "umask": 2
    "download-dir": "/media/usbtmp/transmission",
  • rpc-passwordは、クリアにパスワードを入力してもOK。デーモンを起動したらハッシュに変換してくれる。
  • rpc-whitelist-enabledfalseにするか、rpc-whitelistに許可IP範囲(例:127.0.0.1,10.0.*.*)を設定するかで外部からのアクセスを可能にできる。
  • ファイルは全員が見れる用に umask を設定する。
  • download-dir に指定したパスにファイルがダウンロードされる。

RPCを設定したら、ウェブからアクセスできるようになるので、デーモンを起動し、ウェブ(http://ipaddress:9091/)を開く。


sudo service transmission-daemon start

その他設定

個人的に設定を変更にした箇所。

2c2
<     "alt-speed-down": 100, 
---
>     "alt-speed-down": 50, 
8c8
<     "alt-speed-up": 1, 
---
>     "alt-speed-up": 50, 
15c15
<     "download-dir": "/media/usbtmp/transmission", 
---
>     "download-dir": "/var/lib/transmission-daemon/downloads", 
20,22c20,22
<     "encryption": 2, 
<     "idle-seeding-limit": 1, 
<     "idle-seeding-limit-enabled": true, 
---
>     "encryption": 1, 
>     "idle-seeding-limit": 30, 
>     "idle-seeding-limit-enabled": false, 
43,44c43,44
<     "ratio-limit": 0.0098, 
<     "ratio-limit-enabled": true, 
---
>     "ratio-limit": 2, 
>     "ratio-limit-enabled": false, 
62,63c62,63
<     "speed-limit-up": 10, 
<     "speed-limit-up-enabled": true, 
---
>     "speed-limit-up": 100, 
>     "speed-limit-up-enabled": false, 

ゼロから Core Data を学ぶ

とりあえず読み書きができるまで

プロジェクト作成

Single View Application を作成。
ゼロから作成するので Use Core Data はチェックしない。

Data Model 追加

TestData と名前をつけてプロジェクトに追加。
TestData.xcdatamodeld/TestData.xcdatamodel が作成される。

テストモデルでデータの読み書き

TestModel という Entity を追加し、属性 text: String を追加。

ViewController にボタンを設置し、そのボタンを押すたびにモデルが増えるコードを書く。

import UIKit
import CoreData

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // データをロード
        print("load begin")
        container = NSPersistentContainer(name: "TestData")
        container.loadPersistentStores { (desc, error) in
            if let error = error {
                print("load error: \(error)")
            } else {
                print("load ok: \(desc)")
            }
        }
    }

    @IBAction func testButton(_ sender: Any) {

        let context = container.viewContext

        // データ追加、textに任意文字列設定
        let testModel = NSEntityDescription.insertNewObject(forEntityName: "TestModel",
                                                            into: context)
        testModel.setValue(UUID().uuidString, forKey: "text")

        // 保存
        try! context.save()

        // 列挙
        let request = NSFetchRequest<NSManagedObject>(entityName: "TestModel")
        let models = try! context.fetch(request)
        print("-- model count: \(models.count)")
        for model in models {
            let text = model.value(forKey: "text")!
            print("text: \(text)")
        }
    }

    var container: NSPersistentContainer!
}

ボタンを3回押したときの出力:

load begin
load ok: <NSPersistentStoreDescription: 0x60800004d9b0> (type: SQLite, url: file:///Users/rsahara/Library/Developer/CoreSimulator/Devices/D9D49483-571C-409D-87F2-88556CB3D351/data/Containers/Data/Application/C53CF83C-77F4-4719-BA87-242D158B3DC7/Library/Application%20Support/TestData.sqlite)
-- model count: 1
text: E4AA836E-3F59-4F96-B6EF-CB79EFFA57BB
-- model count: 2
text: E4AA836E-3F59-4F96-B6EF-CB79EFFA57BB
text: 3A64EDFE-D6B2-4C9D-A3AD-4D53DFAD4FFE
-- model count: 3
text: E4AA836E-3F59-4F96-B6EF-CB79EFFA57BB
text: 3A64EDFE-D6B2-4C9D-A3AD-4D53DFAD4FFE
text: F0690E43-8E0A-46B0-A491-482E3E407585

アプリを再起動しても、データは保存されている:

load begin
load ok: <NSPersistentStoreDescription: 0x600000241ce0> (type: SQLite, url: file:///Users/rsahara/Library/Developer/CoreSimulator/Devices/D9D49483-571C-409D-87F2-88556CB3D351/data/Containers/Data/Application/6DE5C1D8-FB7C-48F2-9A38-B2BDF0A8885C/Library/Application%20Support/TestData.sqlite)
-- model count: 4
text: E4AA836E-3F59-4F96-B6EF-CB79EFFA57BB
text: 3A64EDFE-D6B2-4C9D-A3AD-4D53DFAD4FFE
text: F0690E43-8E0A-46B0-A491-482E3E407585
text: F1E3B4FB-9BB9-49CA-B886-C4589A698A5F