2025-02-19

脱獄なしに、Android や iPhone に ssh 接続できる

 

Android スマホや iPhone から ssh サーバーへ接続可能ですが、逆に他デバイスからこれらのスマホへも ssh 接続できます。

 

ともに脱獄は不要です。

 

Android スマホは Termux を使います。

Termux は ssh クライアントと ssh サーバーの両方を動作可能です。

 

openssh をインストールし sshd 設定します。



 

iPhone は iSH を使います。

こちらも ssh クライアントと ssh サーバーの両方を動作可能です。


Termux 同様、openssh をインストールし sshd 設定します。


a-Shell やほかの iPhone 用ターミナルアプリは openssh をインストールできず、sshd (サーバー機能) が使えません。

 

脱獄せずに使えるのは iSH のみです。

 

 

 

次の画面コピーは OPPO Reno11 の Termux 画面です。

 

Termux ssh クライアントから iPhone SE3 の ssh サーバー( iSH で動作)に接続検証していますが、OPPO Reno11 から自分自身の ssh サーバー(Termux で動作)への接続検証もしています。

 


 

 

$ ssh se3

   OPPO Reno11 から iPhone SE3 に接続しにいっています。

 

   se3 は ホームディレクトリ配下の .ssh ディレクトリ内の config ファイルで
   接続先情報を設定しており、接続名が se3 になっています。

 

   また iPhone SE3 は公開鍵認証方式にして、パスワードは不要にしています。

 

   接続中かどうかは env | grep SSH により、接続情報が返ってくるかどうかで
   確認できます。

 

   何も返ってこなければ接続中ではない、ということです。

 

 

$ ssh oppo 

   OPPO Reno11 自身に ssh 接続しにいっています。

 

   oppo は se3 同様に .ssh/config に接続情報を設定しており公開鍵認証方式で
   パスワード不要にしています。

 

 

ちなみに iSH の場合、システム設定でのバックグラウンド更新機能がないので、iSH を cat /dev/location > /dev/null & としてバックグラウンド動作させています。

 

 

 

Termux は設定でバックグラウンド設定ができますので、このような措置は不要です。

 

 

 

本事例では Android スマホから iPhone への ssh 接続と、自分自身への ssh 接続を示しましたが、PC や Mac 等との間でももちろん相互に ssh 接続可能です。 

 

 

このやり方はローカル空間のみで機能しており、グローバル空間には閉じていますので安全です。

 

グローバル空間からは VPN でローカル空間に入れば ssh 接続が機能します。

 

VPN は Tailscale が便利です。

 

 

 

 

 

 

 

 

2025-02-16

iPhone:iSH と Android:Termux の起動時の画面表示内容

 

まず、下図をご覧ください。

 


 

【解 説】

Termux 起動時のシェルスクリプト .bashrc を実行したもの

    1行目:自局ローカル IP(Android スマホの WLAN IP) を表示

    2行目:曜日 月日 時刻 JST 年 を表示

 

起動時に自動実行されるシェルスクリプト .bashrc の内容

    IP アドレスを termux-wifi-connectioninfo から得て整形し表示 

 

    termux-wifi-connectioninfo の実行結果は次で、 で囲んだ部分が自局 IP アドレス

    この中から grep で行を抽出し、余計な記号などを除いて表示している

 

    (ちなみに IP アドレスは ifconfig でも得られる

    date コマンドで 曜日 月日 時刻 JST 年 を得て表示

 

Termux から iPhone:iSH に ssh 接続

    iSH 起動時の画面が表示されるが、オリジナルのものとは異なる

    オリジナルの /etc/motd を変えている

    1〜4行目:変更後の /etc/motd の内容を表示 

    5行目:iPhone のローカル IP を表示 

    6行目:曜日 月日 時刻 JST 年 を表示

    (5〜 6行目は .profile のスクリプト実行結果を表示)

 

起動時に自動実行されるシェルスクリプト .profile の内容

    IP アドレスは python3 プログラム実行で得ている

    (iSH は ifconfig や ip コマンドが使えないため)

       ※ get-my-ip.py は Abo5 氏 作成の、

              https://github.com/ish-app/ish/issues/145 

           からコピペし、一部修正している

    date コマンドで 曜日 月日 時刻 JST 年 を得て表示

 

 

get-my-ip.py のソース内容

    import 行から s.close() 行までが python のソース

 

    最終行の localhost:~# は iPhone:iSH のプロンプト

 

 

 

以上、ターミナルエミュレーターの起動時に表示されるメッセージを編集してみました。

 

 

 

 

 

 

 

 

2025-02-10

ssh 接続先サーバーでコマンドを実行させるクライアント側の ssh 接続の仕方と、ファイル転送

 

【ssh サーバー/クライアント間ファイル転送】記事後半に記載

 

 

ssh クライアントが接続時に「おまじない」をして接続すると接続した ssh サーバーのコマンドを実行できます。

 

 

次に示すのは OPPO Reno11 A の画面コピーです。

 




 

 

【解説】

 

1.Termux 開始後に、最初に "env|grep SSH" としていますが、まだ SSH 接続していないので結果は何も表示されません

 

2.$cmd 変数には " ps;" を設定しています

      これは ssh 接続したときに ssh サーバーで実行するコマンドです

 

3.ssh 接続します

      ssh -t se3 "cmd=$cmd ash" で ssh 接続します

 

      接続先の se3 は iPhone SE3 の iSH に設定の ssh サーバーです

      .ssh/config に次のような設定をすると HOST 名でアクセスできます

         HOST se3 # ホスト名
            HostName 192.168.xxx.yyy # ssh サーバーアドレス
            User root
            Port nnnn


      -t オプションで仮想端末を強制的に割り当てます

 

      "cmd=$cmd ash" はサーバーで実行するコマンドです

      ash はサーバーを close させないためです

      ” ps; ash" と記述しても同じ結果になります

 

4.サーバーでは ls コマンドが自動的に実行されてプロセス状態表示されます

 

5."env|grep SSH" を実行し、結果が返ってきていますので、サーバー側にいることがわかります

 

6.サーバー上で /usr ディレクトリに移動します

 

7.サーバー上で ls コマンドを実行します

      /usr ディレクトリ内のファイル一覧が表示されています

 

 

 

以上のように、サーバーに接続して実行するコマンド(群)やシェルを指定して ssh 接続時に自動実行させることができます。

 

本事例では " ps;" でしたが、" ps; cd /usr; ls;" として一連のコマンド群を順に実行させることができます。

 

 

参考にしたのは下記サイトです。

 

https://qiita.com/ktooi/items/d93778fbc0a60910fbb7

 

 

 

 

 

【ssh サーバー/クライアント間ファイル転送】

サーバーとクライアント間でファイルやフォルダを転送するには次のようにします。

 
■ クライアント側(ローカル側)からリモート側(ssh サーバー側)へ転送

ssh -p [nnnn] [<user][address] 'cat > /[dir]/[file1]' < [file2]

 

   [nnnn]         :ポート番号

   [user]          :ユーザー名

   [address]     :IP アドレス

   [dir]             :リモート側ディレクトリ

   [file1]           :リモート側に保存するファイル名

   [file2]           :ローカル側の現ディレクトリのファイル名

 

例:ssh se3 'cat > /usr/test-file' < test.txt

 

 

■ リモート側からローカル側へ転送の場合

ssh -p [nnnn] [user][address] cat /[dir]/[file3] > [file4]

 

   [file3]           :リモート側から転送するファイル名

   [file4]           :ローカル側の現ディレクトリに保存するファイル名

 

例:ssh se3 cat /usr/test.txt > test.tmp

 

ーーーーーーーーーーーーーーーーーーーー

 

 

 

下図は OPPO Reno11 A の Termux 画面です。

 



 

次図は sshd サーバーである iPhone SE3 の iSH 画面です。

 


 

 

① はローカル(OPPO 側)からサーバー(iPhone)に送る test.txt の中身です

    最終行の日時を確認ください

 

② これをサーバーに送る ssh コマンドですが、受け取ったサーバーでは
    test-file というファイル名で /usr 配下に書き込みます

    ⑤ が受け取ったファイル test-file の中身です

    転送したファイルと同じ日時になっているのが確認できます

 

③ サーバー側の test.txt は ⑥ のよう中身で、これをローカル側に転送し、
    ローカル側では test.tmp として保存します

 

④ ローカル側に保存した test.tmp の中身を表示したもので、⑥ の内容と同じ
    であることを確認できます

 

 

 

 

ssh コマンドのオペランドの内容はサーバー側で接続後に実行するコマンドです。

 

「<」や「>」を含む場合は「”」か「’」で囲みます。

    

 

ssh コマンドは実行後サーバーからは exit します。 

 

サーバーから抜けることで、結果をローカルのファイルとして保存できます。

 

 

以下のようにしても同じ結果が得られます。

 

■ クライアント側(ローカル側)からリモート側(ssh サーバー側)へ転送 

 

下記の ① と ② は同じことです。

 

① ssh se3 'cat > /usr/test-file' < test.txt 

② ssh se3 dd of=/usr/test-file < test.txt 

 

 

リモート側(ssh サーバー側)からクライアント側(ローカル側)へ転送 

 

下記の ③ と ④ は同じことです。

 

ssh se3 cat /usr/test.txt > test.tmp

④ ssh se3 dd if=/usr/test.txt > test.tmp 

 

 

 

 

 

 

 


2025-02-05

iOS の iSH -Alpine Linux- で sshd を自動起動化する【2025-02-08 追記】

【2025-02-08 追記】 iOS の sshd への接続エラー対策

 

iOSiSH 強制終了後の最初の起動を「初期起動」とします。


iSHexit 後は「再起動」され「初期起動」とは異なります。


なにが異なるかといいますと「初期起動」時の自動実行と「再起動」時の自動実行が違うのです。


「初期起動」時に自動実行されたプロセスは「再起動」後も有効です。

 

一方「再起動」時の自動実行は「再起動」のたびに実行されますが、すでに起動されているプロセスがある場合、2重・3重にプロセスが立ち上がります。


 

このような動作になるのは iOS のヘンなポリシー(制限といってもいいでしょう)のせいです。

 

Android の場合、アプリの終了は iOS の強制終了と同等なのでこのような違いは生じません。

 

iOS ってややこしいと思いませんか???

 

 

本記事ではこの違いを踏まえた自動実行化について記載します。

 


januszoles/ish: iPad iSH Alpine Linux Notes

 

の中ほどあたりに、

   Welcome to Alpine on iPhone 6! (2023-04-12)

という箇所に sshd に関する記述があります。

 

この中の、Install and config ssh という項目の記述に従い ssh(sshd) の自動起動化のための処理を行います。

 

openssh のインストールと sshd の設定は済んでいるものとします。

 

$ apk update # リポジトリのアップデート
$
apk upgrade #インストール済みパッケージの最新化
$
apk add openrc # systemctl 相当のパッケージインストール


openrc インストールにより、systemctl 相当のことが可能になります。

 

sshd の起動は次のようにします。


$ rc-service sshd start
grep: /proc/filesystems: No such file or directory
 

 

エラーが出ますが sshd は起動されます。

 

エラーメッセージが出るのはバグっぽいのですが、出ないようにする方法は不明です。

 

* You are attempting to run an openrc service on a
*  * another initialization system to boot this system.
* If you really want to do this, issue the following command:
* ERROR: sshd failed to start
 

要約:このシステムを起動するために、別の初期化システムで openrc サービスを実行しようとしています。

本当にこれを行う場合は、次のコマンドを発行してください:

 エラー: sshd の起動に失敗しました

 

「次のコマンドを発行してください」は次のコマンドです

 

$ /usr/sbin/sshd 

 

こちらはエラーがでません。

 

 

sshdiSH 起動時に自動起動するための登録を、次のようにします。 


$ rc-update add sshd # iSH 起動時に自動起動する登録

 

 

次に iSH をバックグラウンド化する処理を自動化します。

 

バックグラウンド化とは、常に動作状態にして sshd などが終わってしまうのを防ぐことです。

 

Google 検索によると、デーモンには次のような種類があります。


・システム管理系

・タスクスケジューリング系

・ネットワーク系

・周辺機器系

・通信プロトコルサーバ

・電子メール関連

・Samba 関連

・分散メモリキャッシュ関連

・データベースサーバ関連

 

systemd / syslogd / sshd / ftpd / smbd / crond / httpd などなど。

 

これらが勝手に終了状態にならないように、大もとの iSH を常駐化するのです。

 

「初期起動」時にバックグラウンド化するには local デーモンを使います。


 

$ apk add local # local デーモンをインストール

 

このインストールにより /etc/local.d ディレクトリができます。

 

ここに、起動時に読み込むファイルを alpine.start とでもして作成します。

 

ファイル名は任意ですが、拡張子は .start の必要があります。

 

中身は

 

cat /dev/location > /dev/null & # バックグラウンド化
[EOF]

 

です。

 

alpine.start には実行権を与え、local デーモンの自動起動登録をします。

 

$ chmod 700 /etc/local.d/alpine.start
$ rc-update add local

 

いったん iSH を強制終了させ、iSH を「初期起動」します。 


プロセス状態を確認します。

 



画面では PID 84iSH のバックグラウンド化ができていて、236sshd が自動起動されているのが確認できます。

 

 

 

rc-status で自動起動登録したデーモンの状態を確認します。

 


 

Runlevel: defaultsshdlocal が登録されていて、ともに起動済みとなっているのが確認できます。

 

local が起動されると alpine.start が読み込まれ、cat /dev/location > /dev/null & が実行され、iSH のバックグラウンド化がされます。

 

 

 


.profile に記述のスクリプトは iSH「初期起動」時のみならず、exit による「再起動」時も実行されます。



ここに /usr/sbin/sshdcat /dev/location > /dev/null & を記述してもいいのですが、exit による iSH 「再起動」でこれらが実行されると 2重起動状態になってしまいます。


 

なので .profile には exit「再起動」されても 2重起動にならないフォアグラウンドコマンドのみにした方がよいでしょう。



デーモンパッケージは rc-update「初期起動」時の自動起動対象として登録するように使い分けします。



コマンド系(例えば cat /dev/location > /dev/null &)は /etc/local.d に実行ファイル(本事例では alpine.start)を用意するといいでしょう。



現在、ホームディレクトリの .profile には何も設定していませんが、例えば date コマンドを記述すると、exit で再起動されて次のように時刻表示がされます。

 


 

date コマンドは実行されるとプロセスが終了しますので2重起動にはなりません。

 

 

 

 

【2025-02-08 追記】 iOS の sshd への接続エラー対策

 

自動化したものの、ssh で接続できたものが突然に ssh connection refused となったり、no route to host という接続不可事象が発生します。

 

どちらも ping は通りますので、sshd サーバーである iPhone の IP アドレスを誤っているわけではありません。

 

とするとポートが listen されていない、という事象と考えられます。

 

ポートが何らかの原因で閉じられた、と考えるのが普通ですよね。

 

なのでなぜ閉塞されるか、いろいろ調べてもわかりません。

 

本事象は不定期に発生し、一旦発生すると sshd の再起動が必要になり、面倒ですが、原因がわからなくてお手上げ状態でした。

 

 

随分と悩まされましたが、iPhone を WiFi アクセスポイント接続時の dns に IPv6 アドレスを登録していると発生することがわかりました。

 

ポート閉塞ではなかったのです。

 

 

接続してくるクライアントのアドレスが IPv4 で OK だったのを、sshd サーバーが何らかのタイミングで IPv6 での接続とみなし、IPv6 アドレスではないのでこのようなエラーになるようなのです。

 

いったんこの事象に見舞われると sshd の再起動しか回復しませんが、しばらくすると(1時間程度から 12時間程度)また接続エラーになります。

 

 

 

そこで、次の対策を講じました。

 

1.sshd_config の設定変更

      「# AddressFamily any」行を「AddressFamily inet」に変更   

      初期設定はコメントアウトされているのでデフォルトの any になっている

      any は IPv4 と IPv6 のどちらも接続許可する設定

      ⇨ コメントを外し inet(IPv4 のみ接続許可)にする

 

 

2.iPhone の Wi-Fi 設定で「IP を構成」は「手動」

      アドレスを固定するためでもともと「手動」設定している

 

 

3.「DNSを構成」を「手動」にし DNS サーバから IPv6 アドレスを削除する

       念のため DNS を IPv6 で引かないようにする  

 

 

 

以上の対策によって、ssh connection refused や、no route to host で接続不可となっていた問題がなくなり、安定して接続できるようになりました。

 

 

IPv6 が悪さをしていたなんて、誰が気づくというの?

 

 

 

 

 

ちょいと便利な設定

 

iPhone / iSH の sshd サーバのポートは Standard port ではなく Alternative port にします。

 

例えば 22 ではなく 2222 などに変更しますが、これは sshd_config 中の Port 行のコメントアウトを外し、2222 などを設定します。

 

 

クライアント側の ssh_config の Port 行も同じ設定をすると接続時に -p 2222 としないで済みます。

 

Android Termux の場合、/data/data/com.termux/files/usr/etc/ssd/ssd_config を編集します。

 


 

 

iPhone の場合、/etc/ssd/ssd_config を編集します。

 


 

 

 






2025-02-03

iPhone にインストールした iSH - Alpine Linux - のタイムゾーンを UTC から JST に変更する

 

 

iSH は iPhone で使えるターミナルエミュレーターで Alpine Linux です。

 

タイムゾーンがデフォルトでは UTC になっていて、date コマンドで得られる時刻は UTC 時刻です。

 

$ date
Sun Feb  2 22:31:16 UTC 2025

 

「TZ=-9 date」コマンドで時刻補正はできますが、UTC 表示が JST には表示変更されません。

時刻補正であってタイムゾーン変更ではないからです。

 

$ TZ=-9 data
Mon Feb  3 07:32:06  2025

 

面倒ですよね。

 

 

tzdata パッケージをインストールします。


$ apk add tzdata 

 

/usr/share の配下に /zoneinfo ディレクトリができており、その中に Japan というタイムゾーンファイルがあります。

 

$ cp /usr/share/zoneinfo/Japan  /etc/localtime 

 

として、タイムゾーンを /etc/localtime にコピーします。

 

date コマンドで時間補正なしに JST 時刻が得られます。


$ date
Mon Feb  3 07:37:18 JST 2025


JST 表示に変わっていますね。


tzdata は不要なので、

 

$ apk del tzdata

 

として削除します。

 

削除すると /usr/share から /zoneinfo ディレクトリも削除されますが /etc/localtime は影響を受けませんので、問題ありません。

 

 

 

 

 

 

 

2025-01-27

iOS の iSH を使いショートカットでシェルスクリプトを実行させる具体的方法

 

【2025-02-01 追記・他の方法】

ショートカットのアクション「SSH経由でスクリプトを実行」を iPhone 内で実行するやり方で、記事末に記載

 

こちらの方が簡単にできて本命かも!!

 

 

iOS の iSH(Alpine Linux)でシェルスクリプトを自動実行させたい

 

この記事で、シェルスクリプトをショートカットを使って自動実行させる方法についての考え方を記載しました。

 

iSH は Android の Termux 相当のターミナルエミュレーターで、Alpine Linux ベースです。

パッケージを自由に追加できますのでいろいろなことが可能になります。

 

iPhone 向けのターミナルエミュレーターには a-Shell もありますが、こちらは機能が限定的なので、iSH の方が使い勝手が格段によい。

 

 

その iSH で作成したシェルスクリプトをショートカットで実行できると、ショートカットでできることの幅が拡がります。

 

 

 

 

本記事では具体的なやり方を事例を踏まえて記載します。

 

 

1.ショートカットのオートメーションの設定をします

 

ショートカットは、次の事例にします

 

   ・iPhone を電源に接続したとき

   ・アクションでクリップボードに「on」を設定

      アクションはショートカットと iSH に共通に操作可能なものを使います

      本事例ではクリップボードを使っていますが、特定ファイルの有無や、特定ファイルの内容
      なども共通操作可能です

 

クリップボードの内容を、あとに記述の crontab に設定した iSH のシェルスクリプトで判定し「on」ならば目的のシェルスクリプトを実行させます

 

そこで「ショートカット」⇨「オートメーション」右上の + をタップして新しいオートメーションを開始します

 

「充電器」を選び「接続されている」をチェック、「すぐに実行」をチェックし右上の「次へ」をタップ

 

「新規の空のオートメーション」をタップ

 

「アクションを検索」欄に「テキスト」を入力し、現れた「テキスト」アクションをタップ

 

テキスト欄に「on」を入力します


続いて「アクションを検索」欄に「クリップ」と入力します

 

「クリップボードにコピー」アクションを選び、詳細の「有効期限」を「空白」設定します

 

 

つまり、クリップボードに「on」を設定するアクションです

 

同様に「充電器」が「接続解除されている」オートメーションを作成し、こちらの方は「テキスト」に「off」を入力します

 

「電源から接続解除」と「電源に接続」が追加設定したオートメーション
 

 

ショートカット側の設定は以上で終わりです。

 

 

 

2.iSH アプリの設定を変更

 

「設定」⇨「アプリ」⇨「ほかのアプリからペースト」を「許可」に変更します

 

これは iSH がクリップボード参照時に「参照を許可するかどうか」の問い合わせをさせないための設定です

 

 

 

3.ファイルアプリでシェルスクリプトを作成

 

ファイルアプリを開き右下の「ブラウズ」をタップします

 

「場所」⇨「iSH」とし「/usr」をタップ

 

chk.sh という名前のシェルスクリプトを作成します

 

これは「判定要素(本事例ではクリップボードの「on」「off」)を確認」するシェルスクリプトで crontab から呼び出されます

 

次のような内容です

 

res=$(cat /dev/clipboard) #クリップボードの内容を得る
if [ $res = "on" ]; then #クリップボードの内容が "on" なら
   sh /usr/swstat.sh # swstat.sh を実行
   echo "off" > /dev/clipboard #クリップボードに "off" を設定
fi

 

クリップボードが「on」ならば目的のシェルスクリプト swstat.sh を実行し、クリップボードを「off」設定します

 

 

目的のシェルスクリプト swstat.sh を作成します

 

内容は次のようなスクリプトです

 



 

SwitchBot plus の状態を得て、結果を /usr 配下の stat というファイルに書き込むスクリプト事例ですが、かなりいろいろな処理を含んでいます

 

本事例は uuidgen / openssl / curl を追加パッケージとしてインストールし、トークン・Unix time・nonce を合成した認証情報を生成して base64 でエンコードして curl を叩いています

 

Unix time をミリ秒で得るため coreutils もインストールして date コマンドでミリ秒にしています


結果は stat というファイルに書き込みしています


また UTC 年月日時刻を JST 年月日時刻に変換して、stat ファイルに追記しています

 

 

このシェルスクリプト事例は SwithBot plus の状態を得ていますが、もちろん SwitchBot plug のオン・オフ制御も可能です。

 

なので、それを使って例えば 80% 充電したら SwitchBot plug をオフにする、といった自動化も可能になります。

 

 

スクリプトは実際に実行させたいものを作成すればよい

 

 

 

 

4.iSH での作業

 

iSH を起動します

 

crontab -e として編集開始し、次の設定をします


* * * * * for i in `seq 0 10 59`; do (sleep ${i}; sh /usr/chk.sh ) & done;


10秒ごとに chk.sh をバックグラウンドで起動する crontab です


iSH のプロンプトで次のコマンドを入力して2つのシェルに実行権を与え、crond で cron デーモンを起動します

 

また、iSH をバックグラウンドで動作させます

 

$ cd /usr # /usr にディレクトリを移動する
$ chmod 700 chk.sh swstat.sh # chk.sh と swstat.sh に実行権を与える
$ crond # cron デーモンを起動
$ cat /dev/location > /dev/null & # iSH バックグラウンド化のおまじない

 



5.オートメーションのアクションをテスト

/usr 配下の stat ファイルに swstat.sh 実行結果が書き込まれるかをアクションテストで確認する


ショートカットのアクションの右下にある をタップしてアクションをテストします

 

「電源に接続」のアクション内容



このアクションではクリップボードに「on」を書き込んでいます

 

「on」になると crontab で設定した chk.sh での判定が真になり、swstat.sh が実行されます

 

その結果 /usr 配下の stat ファイルには次のような内容が書き込まれます

 


 

 

実際に iPhone を電源に接続すると目的のシェルスクリプトが実行されます。

 

また電源から切断するとクリップボードにはショートカットによって「off」が設定されて chk.sh は何もしない判定になります。

 

 

 

以上が任意のシェルスクリプトをショートカットから実行させる具体事例です。

 

本事例では 10秒間隔で「判定要素を確認」なので、実際にシェルスクリプトが実行されるまでに最大 10秒のタイムラグが発生しますが、実際的に問題はないでしょう。

 

 

「ショートカットでシェルスクリプトを実行できる」ことが重要ですから。

 

 

 

 

 

【2025-02-01 追記・他の方法】

ショートカットのアクション「SSH経由でスクリプトを実行」を iPhone 内で実行するやり方

 

iSH で sshd を動作させ、ショートカットでこの sshd に ssh で接続してシェルやコマンド(群)を実行させるやり方です。

 

参考: https://github.com/januszoles/ish

このサイトの[📎SSH from the same device (not tested yet)]に「未テストだが同じデバイスから ssh する」とあり、下記の記述があります。

 

if you are trying to connect via ssh from the same device, make sure you set the port configuration of sshd to use a non standard one (greater than 1024, eg: 22000) .  You can do this by editing  /etc/ssh/sshd_config  and set Port 22000 (Replace 22000 with any non-standard port).  After this, you can ssh (from iSH itself) using  ssh root@localhost -p 22000

 

このサイトに書かれているとおりに設定してみました。

 



iSH を開きます。

 

$ apk add openssh # openssh をインストール
$ passwd # 接続用パスワードの設定


[ファイル]⇨[etc ディレクトリ]⇨[ssh ディレクトリ]⇨[sshd_config を開く(エディターが開く)]


・13行目の「# Port 22000」のコメントを外す

・最終行の「PermitRootLogin yes」を確認「no」となっていた場合「yes」に変更

・保存して編集を終了

 

 

$ cat /dev/location > /dev/null & # iSH をバックグラウンド動作

$ /usr/sbin/sshd # sshd を起動(ssh サーバーとして起動)

 

 

ショートカットを開き、アクション「SSH経由でスクリプトを実行」を選択し、下図のように設定します。

 


 

スクリプト欄には実行させたいシェルスクリプトやコマンド(群)を記述し、ショートカット名を「シェル実行」とでもします。

 

 

ホストは iPhone 自身を示す localhost(127.0.0.1)を指定します。

 

ポートは 22000 を指定します。

 

ユーザは root を指定します。

 

認証は「パスワード」を選択し、その下のパスワード欄に passwd コマンドで設定したパスワードを設定します。

 

公開鍵認証方式にすることもできます。

その場合はパスワード設定(入力)は不要です。

 

 

 

右上の完了をタップして設定は終わりです。

 

 

本事例のシェルスクリプトは swstat.sh というシェルファイル名で内容は次図です。

 


 

ショートカットを開きます。

 


 

左上の「シェル実行」が作成したショートカットです。

 

これをタップすると ssh で iPhone 自身に接続して swstat.sh を実行します。

 

結果は stat というファイルに書き込まれます(下図)。

 

 


 

 

 

 

 

 

 

2025-01-24

iOS の iSH(Alpine Linux)でシェルスクリプトを自動実行させたい

 

iOS のショートカットはシェルスクリプトを iPhone で実行するようなアクションを起こすことができません。

 

「SSH 経由でスクリプトを実行」というのはリモートコンピューターでスクリプトを実行するもので、結果は stdout で得られますが、スクリプトを iOS 内で実行はできません。

 

 

iSH をインストールすれば Alpine Linux エミュレーターを iPhone で使うことができ、任意のシェルスクリプトを作成して iSH 内で実行できます。

 

しかし、このときのシェルスクリプトを iPhone のショートカットから実行させることができないのです。

 

iPhone のショートカットには iPhone 内でショルスクリプトを実行させる仕組みがないのです。

 

iSH の開始時に自動でシェルスクリプトを実行させることは可能なのですが、2度目以降の開始時には自動実行されません。

 

これはアプリが終了していないからで、ホームボタンを二度タップ後に現れるアプリリストをスワイプして初めて次の開始時に自動実行されます。

 

Android の Termux は起動時シェルスクリプト自動実行が可能で、exit 後に再度開けばこれが機能します。

 

iPhone はこのような動作にはならないので、起動時シェルを設定しても意味がありません。

 

 

なお iPhone にはワンタップでアプリを終了させる機能がありません。

 

そのためかショートカットにアプリを終了させるアクションがない、ということでしょう。

 

 

このような、iPhone とそのショートカットの制約(不完全さ、といっても過言ではないでしょう)ゆえにまともな自動化ができません

 

 

 

Android には Tasker、Macrodroid、Automate などの優れた自動化アプリがありますが、iOS には同等のアプリがありません。

 

また Termux: Tasker プラグインをインストールすれば Tasker や Macrodroid で任意のシェルスクリプトを実行することができますが、iPhone はこういうことができません。

 

 

アップルのポリシーという闇のせいで Android では可能な自動化が同等にはできず、やると違反アプリとして削除されてしまうでしょう。

 

実は iSH も一度削除の憂き目に会っています。

 

 

iOS 上の iSH は自分で終了するコマンドが空振りします。

 

   ・exit コマンドは再起動されてしまい、終了しないのです

   ・poweroff コマンドは空振りします

 

ベースとなっている Alpine Linux 自体は exitpoweroff で終了します。

 

これは iOS のせいなのか、iOS 上の iSH の仕様なのかはわかりません。


推定ですが、アップルのポリシーに抵触しないように、iSH 側で「終了」させないようにしているのではないか、と。

 

なんとも半端な欠陥品ともいえるショートカットであり、iPhone 自体の制約でできないことがもどかしい状態です。

 

以上のようなこともあって、わたしは iPhone よりも Android の方が好みです。

 

 

 

 

いずれにせよ、ない知恵を絞り、どうすればシェルスクリプト自動実行を、ショートカットと iSH で代替できるか、を考えてみました。

 

 

1.「ある判定」をするシェルスクリプトを組み、cron を使って例えば 10秒ごととか、30秒ごととか、1分ごととかにこのスクリプトを動作させます。

 

「ある判定」要素はショートカットで設定しますが、ショートカットと iSH シェルスクリプトに共通的に操作可能な要素にします。

 

例えば、

 

   ・特定のファイルが特定のフォルダに存在するか否か

      特定ファイル名の変更で「存在」、「非存在」を判定

   ・特定のファイルの「内容」で判定

   ・クリップボードの「内容」で判定

    など

 

です。

 



2.ショートカットで設定された「ある判定」要素が、スクリプトでの判定条件に一致の場合に、「ある判定」を行うスクリプトが「別のスクリプト」を実行するのです。

 

「別のスクリプト」がショートカットで実行させたい目的のスクリプトです。

こうすることによってショートカットで設定した判定要素に従って目的のスクリプトを実行させることが可能になります。

 

判定時間間隔は、通常の crontab 設定では最小が1分ですが、crontab 設定を工夫すれば1秒以上の任意の時間間隔で判定するようにできます。

 

 

 

3.以上を実現するために、iSH で cron を使います。

 

iSH は Alpine Linux のエミュレーターで、crontabcrond は標準で入っています。

 

iSH はまた、パッケージを追加できますのでコマンドラインでいろいろなことが可能になります。


crontab には次の設定をします。

 

   * * * * * for i in `seq 0 10 59`; do (sleep ${i}; コマンド) & done;

 

例は 10秒間隔でコマンドを実行します。

 

コマンド部分は「ある判定」をするシェルスクリプトを設定します。

 

「ある判定」をするシェルスクリプトはバックグラウンドで動作させますが( 設定)、これはコマンドの実行にかかる時間が次のコマンド実行開始時間のズレになるのを防止のためです。

 

判定が一致の場合に「別のスクリプト」を実行するようにし、cron がループ処理に陥らないように「判定条件を不一致」に変更します。

 

crond の停止は kill $(pidof crond) とするとできます。

 

これによりシェルスクリプト内で crond を停止処理することができます。

 

こうすることで任意の時間間隔で「ある判定」が可能になります。 

 

時間間隔を大きくすれば、スクリプト実行までのタイムラグが生じますし、小さくすればタイムラグが少なくて済みますが、あまり小さくするとバッテリー消費が多くなります。

 

10 〜 30秒程度かな?   と。

ーーーーーーーーーーーーーーー

 

 

 

 

iSH を、iPhone のロック中でも動作させ続けるためバックグラウンド化します。

 

これは次のおまじないをします。

 

   cat /dev/location > /dev/null &

 

そして crond をコマンド入力して cron のデーモンを起動します。

 

ps a で "cat /dev/location" と "crond" タスクの起動状態を確認します。

 

 

実は cat /dev/location はバックグラウンド動作のため結構バッテリーを消費します。

 

これに比べれば crond でのバッテリー消費は大したものではありません。

 

 

 

以上のような、ショートカットと iSH 連携によって、ショートカットのアクションにより、目的のシェルスクリプトが実行できる具体的なやり方は本ブログに記載予定です。

 

 

 

 

 

 

 

 

2025-01-12

iPhone で unix time をミリ秒で得る 〜 Termux 代替の iSH を使う【2025-01-14 書き直し】

 

 

Android の Termux 相当を iPhone で実現するには iSH や a-shell アプリというターミナルエミュレーターがあります。

 

残念なことに Termux: Widget や Termux: Tasker プラグインのような仕組みはありません。

 

なので、作成したシェルスクリプトをウィジェット化してワンタップで実行するとか、プラグインで Tasker や MacroDroid で自動化する、というようなことはできません。

 

 

しかし iSH はパッケージを自由に追加可能な Alpine Linux です。


ターミナルエミュレーター機能に限れば Termux 相当といえるでしょう。


iSH のディレクトリやファイルを iOS のファイルアプリで扱えるので GUI エディターが使え、シェルスクリプトを作成・編集できます。

 

 

iSH とエディター LiquidLogic をインストールします。

 

 

iOS のファイルアプリで iSH のディレクトリにアクセスできますから、いつでもスクリプトを編集できます。

 


 

 

iSH で下記のスクリプト(SwitchBot plug の状態を確認するスクリプト)を作成し、任意のディレクトリに SW_stat.sh という名前で格納し、実行権を与えておきます。

 

ーーーーーーーーーー ここから ーーーーーーーーーー
deviceid
="<デバイスID>"
token="<トークン>"
secret="<クライアントシークレット>"
t=$(date +%s%3N)
nonce=$(uuidgen -r)
sign=$(echo -n ${token}${t}${nonce} | openssl dgst -sha256 -hmac ${secret} -binary | base64)

curl -sS -X GET "https://api.switchbot.net/v1.1/devices/${deviceid}/status"
\
-H "sign: ${sign}" \
-H "t: ${t}" \
-H "nonce: ${nonce}" \
-H "Content-Type: application/json; charset=utf-8" \
-H "Authorization:  ${token}" \
 | cat > ./SW_stat.txt

cat ./SW_stat.txt
echo ""
ーーーーーーーーーー ここまで ーーーーーーーーーー

 

 

これを実行して、SwitchBot plug の状態を確認してみます。

 

そのため iSH で、必要なパッケージをインストールします(echo や cat, base64 は iSH に最初から入っています)。

 

   ~$ apk add uuidgen openssl curl


そして作成したシェルスクリプト SW_stat.sh を実行します。


   ~$ ./SW_stat.sh


結果はエラーでうまくできません。

コマンドラインを一つずつ検証したところ、

 

   t=$(date +%s%3N)

 

この部分でちゃんとミリ秒が得られていないためということがわかりました。

 

改めて date コマンドを検証してみます。

 

   ~$ date +%s%3N
   17366467533N

 

結果は 10桁(秒)に文字列 "3N" がくっついています。


Mac のターミナルで date を検証してみると、上記と同じで 10桁(秒)に文字列 "3N" がくっついてしまいます。

 

 

まずは Mac で brew を使って coreutils をインストールし、GNU 版 date コマンドの gdate でミリ秒が得られました。


   ~$ gdate +%s%3N
   1736647342397

 

Mac と同様に iSH 上で coreutils をインストールして、

 

   ~$ gdate +%s%3N

 

としますが、そんなコマンドはないよと叱られます。

 

ですが coreutils インストールによって、date コマンド自体がミリ秒に対応したことがわかりました。

 

   ~$ date +%s%3N
   1736649967217
 

 

と、13桁のミリ秒を得ました。

 

 

unix time のミリ秒を得るコマンドが Mac と iPhone の iSH で異なるのは、macOS が BSD なのに対して iPhone に入れた iSH が Alpine Linux のためでしょう。

 

 

 

ともあれ date コマンドで unix time ミリ秒が得られるようになりましたので、改めて前記のシェルスクリプトを実行してみます。


   ~$ ./SW_stat.sh

 

curl 実行結果を書き出した SW_stat.txt の内容は下記のように得られ、問題なく処理できました。

 

   ~$ cat SW_stat.txt
   {"statusCode":100,"body":{"version":"V2.0-
   2.0","power":"on","voltage":99,"weight":5.9,
   "electricityOfDay":81,"electricCurrent":95,
   "deviceId":"<デバイス ID>","deviceType":"Plug Mini (JP)",
   "hubDeviceId":"
<デバイス ID>"},"message":"success"}

 

 

iSH が Termux の代替になることを確認できましたが、さてどのように活用しましょうか。

 

 

iSH で作成・保存したシェルスクリプトをショートカット化できると面白いのですが、いまのところできるのかどうかわかっていません(多分、できなさそう (;_;) )。