お知らせ:


 ◇ YouTube Apple Japan チャンネル で有用なヒントや使い方を配信中です。
 ◇ iOS 向け Apple サポート App のバージョン 2.4.1 が公開されました。

しばらく返答が寄せられていないようです。 再度ディスカッションを開始するには、新たに質問してください。

質問:

質問: シェルスクリプトの動作について

質問は2 つです。シェルスクリプトを起動時にlaunchd から読んだ際にType A とType B の動作の違いは何故か。

memory_pressure コマンドを読んだ際に、再起動前のFinder のウインドウが開かなくなるのは何故か。

です。


状況ですが、

勉強がてら下記のシェルスクリプトを作りました。勉強しながら作ったので、その手の人が見るとダメダメな可能性が高いすが、どうにも不思議な動きをするので質問することとしました。

下記のシェルスクリプトはThunderbolt 接続の外付けSSD から起動したさいにVM パーティションをマウントするためのものです。

Type A

#!/bin/bash -x



set -eu



UUID=「自分のところのUUID」

mountpoint=""

tpoint="/private/var/vm"

vmSwap="vm.swapusage: total = 0.00M"

swapfile="vm.swapusage: total = 0.00M"



sleep 7



for n in $(seq 1 5)

do

if [ "$mountpoint" = "$tpoint" ] ; then

echo $((n - 1)) >> /Users/Shared/n.txt

else

set +e

diskutil mount -mountPoint /private/var/VM "$UUID"

set -e



sleep 4

mountpoint=$(diskutil info "$UUID" | grep -o "$tpoint")

echo ${mountpoint}" xx" >> /Users/Shared/n.txt

fi

done



set +e

memory_pressure -l critical 2>&1 &

set -e



sleep 7



set +e



for n in $(seq 1 61)

do

if [ "$swapfile" = "$vmSwap" ] ; then

sleep 2

swapfile=$(sysctl vm.swapusage | grep -o "$vmSwap")

else

killall -15 -e memory_pressure

exit 0

fi

done

それでType B

#!/bin/bash



UUID=「自分のところのUUID」

mountpoint=“”

mou="vate/var/vm (apfs, local, nodev, nosuid, journaled, noowners, nobrowse)"



for n in `seq 1 14`

do

if [ "$mou" = "$mountpoint" ] ; then

echo $n >> /Users/Shared/Logs/n.txt

exit

else

diskutil mount -mountPoint /private/var/vm $UUID

fi



sleep 3

mountpoint2=`mount | grep "s4 on /private/var/vm (apfs,"`

mountpoint=${mountpoint2##*pri}

done

提載状態なら、どちらも正常に動きます。

それで、

最初の質問はType A の8 行目「sleep 7」です。Mac によってはこの「7」が4 以下になると動きません。動かないのにエラーは出ません。ログによれば目的のパーティションはマウントされて終了しています。ところがログイン後、確認するとマウントされていません。

これは何故でしょうか。これが第一の質問です。


第二の質問ですが、Type A のmemory_pressure コマンドです。

何故かType A の上記のコマンドを実行するとMac を起動してログインしたさいに再起動前に開いていたウインドウが開かなくなる症状があります。私のところでは再現性は高いのですが、気まぐれに起きなくなったりします。気まぐれに直るのは良いのですが何故、起きるのでしょうか。


macOS High Sierra 10.13.4

投稿日

返信

ページコンテンツが読み込まれました

2018/04/17 14:06 ni_ki への返信 ni_ki への返信

ディスク情報を得るコマンドは、df、mount、diskutilなどがありますが、以前、私が試した限りではdfが一番はやかったです。


8行目のsleepがないと動かないとのことですが、不可解ですね。seqの数を増やしてもだめなんですか?

また、"diskutil mount"を何度も発行するのは良くないと思います。


というわけで、私ならこうします。


device=$( diskutil mount -mountPoint /private/var/vm $UUID | swk '{ print $4 }') mounted=0 if [ $device != "" ]; then for n in $(seq 0 120); do if [ $mounted -eq 1 ]; then echo $n >> /Users/Shared/Logs/NumberOfSeconds.txt break else mounted=$(df -b -T apfs | grep -c $device) fi sleep 1 done fi


memory_pressureはわかりません。

2018/04/17 14:06

返信 参考になった

2018/04/17 20:04 hohokihai への返信 hohokihai への返信

hohokihai さんによる書き込み:


8行目のsleepがないと動かないとのことですが、不可解ですね。seqの数を増やしてもだめなんですか?

厳密には動かないのではなくログによれば1 回目のdiskutil mount の実行でマウントを完了して正常終了しているようです。ところがログインが完了してから確認するとマウントされていません。seq の方は1 回目ので正常完了とされているので増やしても動作に変わりありません。

というわけで、私ならこうします。


device=$( diskutil mount -mountPoint /private/var/vm $UUID | swk '{ print $4 }') mounted=0 if [ $device != "" ]; then for n in $(seq 0 120); do if [ $mounted -eq 1 ]; then echo $n >> /Users/Shared/Logs/NumberOfSeconds.txt break else mounted=$(df -b -T apfs | grep -c $device) fi sleep 1 done fi


確認してみたのですがdf コマンドの行の「grep -c $device」ですが、このgrep はUUID が含まれる行数を計算するものでしょうか。

2018/04/17 20:04

返信 参考になった

2018/04/18 15:07 ni_ki への返信 ni_ki への返信

実は私、起動時にRamdiskをmountするアプリを作っているのですが、Yosemiteの頃からmacOSが勝手にunmountするようになったので、mountする直前にdiskarbitrationdやfseventsdをkillして凌いでいました。(それでもunmountされてしまうこともありました)


Yosemiteではsystem.logにkernelがunmountしたとのログが残っていましたが(mountしてから約8秒後)、Sierraではsystem.logにも記録されなくなりました。これらはセキュリティ強化の一環なのでしょう。


その後、フォーマットをHFS+からGPTに変えたら、小細工せずともunmountされなくなったので(High Sierraにした現在でも動いています)、GPTコンテナの中にあるAPFSも問題ないと思ったのですが、今回の場合ももしかするとmacOSが勝手にunmountしているのかもしれません。


mountした直後に、macOSが勝手にunmountしているのであれば、diskutil mountを連続して行うのも仕方がないのかもしれません。しかし何故、連続で行えば成功するのか釈然としません。


> dfコマンドの行の「grep -c $device」ですが、このgrepはuuidが含まれる行数を計算するものでしょうか。


$deviceには「disk1s4」が入っている筈です。従って、grepは「disk1s4」が含まれる行数です。


launchd.plistは、/Library/LaunchDaemonsに入れてます?/Library/LaunchAgentsですか?


ところで今回の動機は、APFSでフォーマットした外部SSDから立ち上げたとき/var/vmが起動時にマウントされない問題絡みですよね?


MacBookであれば、下記を設定すればバッテリーがなくならない限りスリープしなくなるので、/var/vm/sleepimageの書き換えはまず起こらなくなり、/var/vmをマウントせずとも平気かもしれません...?


sudo pmset -a autopoweroffdelay 90000 # 25h

sudo pmset -a hibernatemode 0

sudo pmset -a standby 0

2018/04/18 15:07

返信 参考になった

2018/04/18 15:39 hohokihai への返信 hohokihai への返信

書き込みありがとうございます。grep の件、了解です。なぜかdevice にはUUID が入っているのでawk の方を確認してみます。

plist 置き場はDaemons の方です。マウント理由はお考えの通りですが、スワップファイルが作成されない問題の対策です。なのでスリープだと凌げません。

2018/04/18 15:39

返信 参考になった

2018/04/18 16:27 ni_ki への返信 ni_ki への返信

失礼しました、UUIDでした...

ユーザがアップロードしたファイル

私の環境では、VMのサイズは4.3GB、sleepimageは4GBで、swapfileをつくるスペースがないように思うのですが...

ユーザがアップロードしたファイル

2018/04/18 16:27

返信 参考になった

2018/04/18 16:49 ni_ki への返信 ni_ki への返信

度々すみません。実のところTerminal.appでユーザーがVMをマウントすることが可能なので、システム起動中に実行される/Library/LaunchDaemonsではなく、ログイン後に実行される/Library/LaunchAgentsに入れたら勝手にunmountされることはない、なんてことありませんか?

2018/04/18 16:49

返信 参考になった

2018/04/18 23:01 hohokihai への返信 hohokihai への返信

やっぱりUUID ですよね。マッチングする文字列を変更いたしました。ただやはり最初にsleep 5 とかを入れないと不安定なようです。

また再起動でウインドウがすべて閉じる症状はmemory_pressure コマンドが原因ではないようです。hohokihai さんのスクリプトでも発生しました。何かのタイミングのようですね。

またお示しのVM パーティションの4.3GB はパーティションの使用量だと思われます。

私にところで試した際には30GB くらいまではスワップいたしました。

Launched のplist の置き場所は試してみます。

ありがとうございます。

2018/04/18 23:01

返信 参考になった

2018/04/19 00:41 hohokihai への返信 hohokihai への返信

サラッと試してみましたがAgents の方はroot 権限で実行されるのではないのですね。管理者権限だとsudo が必要になるのでexpect の方に戻さないといけないようです。

2018/04/19 00:41

返信 参考になった

2018/04/19 01:59 ni_ki への返信 ni_ki への返信

横から失礼します。


サラッと試してみましたがAgents の方はroot 権限で実行されるのではないのですね。管理者権限だとsudo が必要になるのでexpect の方に戻さないといけないようです。


セキュリティ的にはちょっとアレだけど...、こんな感じで sudo の -S オプションを使ってみてはどうでしょうか?

echo 'password' | sudo -S whoami

2018/04/19 01:59

返信 参考になった

2018/04/19 12:51 Hiro.S への返信 Hiro.S への返信

-S オプションはまだ試せていないですが、書込みありがとうございます。

とりあえず以前、作成してあったexpect の方で試したところログアウトでアンマウントされてしまいました。再ログインで再マウントされるのですが。

2018/04/19 12:51

返信 参考になった

2018/04/19 13:24 ni_ki への返信 ni_ki への返信

> 管理者権限だとsudo が必要になるので


あ、そうでしたっけ。思いつきで書いてしまって申し訳ないですw


外付けのSSD持っていないので、インターナルSSDで試してみました。インターナルの場合、正常にマウントされるので、はじめにumoutしています。


com.example.vmmount.plist

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Label</key> <string>com.example.vmmount</string> <key>LaunchOnlyOnce</key> <true/> <key>LowPriorityBackgroundIO</key> <true/> <key>ProgramArguments</key> <array> <string>/Library/PrivilegedHelperTools/vmmount.sh</string> </array> <key>RunAtLoad</key> <true/> </dict> </plist>

vmmount.sh

#!/bin/bash -u vmlog() { echo "$(date '+%b %d %H:%M:%S') ${0##*/}: $1" >>/Library/Logs/vmmount.log } vmlog "Start..." while [ "$(ps -A -o command | grep -c loginwindow)" = 0 ]; do vmlog "Waiting for loginwindow to launch..." sleep 1 done mounted=$(df -b -T apfs | grep -c /dev/disk1s4) if [ $mounted -eq 1 ]; then vmlog "Unmount APFS Volume VM" umount /dev/disk1s4 fi mounted=$(df -b -T apfs | grep -c /dev/disk1s4) if [ $mounted -eq 0 ]; then diskutil mount -mountPoint /private/var/vm /dev/disk1s4 >/dev/null 2>&1 if [ $mounted -eq 0 ]; then for n in $(seq 0 15); do if [ $mounted -eq 1 ]; then vmlog "APFS Volume VM on /dev/disk1s4 Mounted." break else mounted=$(df -b -T apfs | grep -c /dev/disk1s4) fi sleep 1 done fi if [ $mounted -eq 1 ]; then for n in $(seq 0 15); do if [ $mounted -eq 0 ]; then vmlog "APFS Volume VM on /dev/disk1s4 Unmounted." break else mounted=$(df -b -T apfs | grep -c /dev/disk1s4) fi sleep 1 done fi else vmlog "APFS Volume VM already mounted." fi vmlog "Stop..." exit 0

vmmount.log

ユーザがアップロードしたファイル


最初に"loginwindow"が立ち上がるまで待つルーチンを入れてみましたが、3回試した内の1回しか実行されませんでした。Unmountを検出するルーチンは一度も実行されず。リスタートする前に起動させていたのはTerminalのみですが、画面にあるとおりリストアーされてます。


システム終了前に開いているアプリの情報は、~/Library/Saved Application Stateに保存されるのでVMとは無関係に思うのですが、何なのでしょうね?

2018/04/19 13:24

返信 参考になった

2018/04/19 19:40 hohokihai への返信 hohokihai への返信

検証、感謝申し上げます。

どうも起動やログイン時のマウント系が不思議な動作をするようですね。もしかして外付けAPFS から起動すると、vm パーティションをマウントしないのもスワップファイルを作成しないのも、似た原因なのかと勘ぐってしまいます。


ちなみに別の外付けSSD を指定したら見事にマウントされてスワップもできました。何か楽しいですね。

2018/04/19 19:40

返信 参考になった

2018/04/21 22:09 ni_ki への返信 ni_ki への返信

前にも書き込んでいますが、やはりdiskutil mount コマンドを使う前に時間を置くのが最善なようです。

sleep 17

くらいから、我が家の複数のMac で安定します。


ちなみに別ストレージをVM にマウントしていて、それを強制的にアンマウントするとクラッシュします。当然ですね。

2018/04/21 22:09

返信 参考になった

2018/04/22 14:24 ni_ki への返信 ni_ki への返信

> 前にも書き込んでいますが、やはりdiskutil mount コマンドを使う前に時間を置くのが最善なようです。

> sleep 17

> くらいから、我が家の複数のMac で安定します。


そうですか。前のサンプルではloginwindowが起動するのを待ちましたが、それよりも後に起動するWindowServerやSystemUIServerを待つというように、プロセスを変えるのも手だと思います。

2018/04/22 14:24

返信 参考になった

2018/04/22 21:49 hohokihai への返信 hohokihai への返信

それらのプロセスがある時から17 秒後か、その前かで動くかどうか決まりそうですね。

もっとも「ある時」がいつかはわかっていませんから起動時のOS のログとシェルスクリプトの起動時間を比べれば何かわかるのかも知れないです。

今回の件ではシェルスクリプトが動かないのではなくマウント後に何かがマウント済みのvm パーティションをアンマウントしているようですので、そこら辺調べると面白そうです。

時間が取れたら調べてみます。

2018/04/22 21:49

返信 参考になった
ユーザのユーザプロフィール: ni_ki

質問: シェルスクリプトの動作について