From bdf6f7319fe5a028049a41ae5fb4068bd386a064 Mon Sep 17 00:00:00 2001 From: Doug Luce Date: Tue, 15 Jul 2025 14:33:41 -0700 Subject: [PATCH 1/3] Add `ramdisk status` Which displays the underlying device and size (in GiB) for the attached ramdisk. Command validation is moved to the bottom of the routine as a fallback. This elides one place of repetition. --- src/ramdisk.sh | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/src/ramdisk.sh b/src/ramdisk.sh index 43798d0..f3614b9 100644 --- a/src/ramdisk.sh +++ b/src/ramdisk.sh @@ -2,14 +2,9 @@ ramdisk() { local cmd size blocks device backing mp="/Volumes/RAMDisk" - # validate command - if [[ $1 != create && $1 != destroy ]]; then - echo "Usage: ramdisk create | destroy" >&2 - return 1 - fi cmd=$1 - # Create + # Create if [[ $cmd == create ]]; then # require exactly two args if (( $# != 2 )); then @@ -61,7 +56,30 @@ ramdisk() { return 0 fi - # Destroy + # Status + if [[ $cmd == status ]]; then + # no extra args + if (( $# != 1 )); then + echo "Usage: ramdisk status" >&2 + return 1 + fi + + # check if mounted + if [[ ! -d $mp ]]; then + echo "Error: no RAMDisk found at $mp. use \`ramdisk create\` for new volume." >&2 + return 1 + fi + + echo "→ RAMDisk mounted at $mp" + diskutil info -plist /Volumes/RAMDisk | tee \ + >(plutil -extract TotalSize raw - | + awk '{print " → size: " $1/1e9 " GiB"}') \ + >(plutil -extract DeviceNode raw - | + awk '{print " → device: " $1}') > /dev/null + return 0 + fi + + # Destroy if [[ $cmd == destroy ]]; then # no extra args if (( $# != 1 )); then @@ -100,6 +118,7 @@ ramdisk() { echo "✔ RAMDisk at $mp destroyed" return 0 fi -} - + echo "Usage: ramdisk create | status | destroy" >&2 + return 1 +} From 2a174a3efc5e900a0090e829b0146f90c62a7ff5 Mon Sep 17 00:00:00 2001 From: Doug Luce Date: Tue, 15 Jul 2025 14:33:41 -0700 Subject: [PATCH 2/3] Add a couple more stats to the status output Also fix GiB (it was GB) and abstract the human-readable byte display (cribbed from https://unix.stackexchange.com/a/4691/115271). --- src/ramdisk.sh | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/ramdisk.sh b/src/ramdisk.sh index f3614b9..4cbb4c3 100644 --- a/src/ramdisk.sh +++ b/src/ramdisk.sh @@ -72,8 +72,12 @@ ramdisk() { echo "→ RAMDisk mounted at $mp" diskutil info -plist /Volumes/RAMDisk | tee \ - >(plutil -extract TotalSize raw - | - awk '{print " → size: " $1/1e9 " GiB"}') \ + >(plutil -extract TotalSize raw - | nfmt | + awk '{print " → size: " $1}') \ + >(plutil -extract CapacityInUse raw - | nfmt | + awk '{print " → in use: " $1}') \ + >(plutil -extract APFSContainerFree raw - | nfmt | + awk '{print " → free: " $1}') \ >(plutil -extract DeviceNode raw - | awk '{print " → device: " $1}') > /dev/null return 0 @@ -122,3 +126,15 @@ ramdisk() { echo "Usage: ramdisk create | status | destroy" >&2 return 1 } + +nfmt () { + awk ' + function human(x) { + if (x<1000) {return x} else {x/=1024} + s="kMGTEPZY"; + while (x>=1000 && length(s)>1) + {x/=1024; s=substr(s,2)} + return int(x+0.5) substr(s,1,1) "iB" + } + {sub(/^[0-9]+/, human($1)); print}' +} From c1ca03ceb120cc0e974ecff8f48ebac670293bd2 Mon Sep 17 00:00:00 2001 From: Doug Luce Date: Tue, 15 Jul 2025 15:50:05 -0700 Subject: [PATCH 3/3] Fix Bash and refactor I tested this manually in ZSH and had pushed without making sure Bash had no problems. Turns out it did, the command would complete and dump the user back at the prompt before all the output was done. Adding cat at the end of the pipeline ensures that Bash will not return until the subprocesses have completed. This seems to address the issue. I've also centralized some of the repeated complexity within the pipeline at the cost of simpler repetition. --- src/ramdisk.sh | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/ramdisk.sh b/src/ramdisk.sh index 4cbb4c3..22d8dcc 100644 --- a/src/ramdisk.sh +++ b/src/ramdisk.sh @@ -1,4 +1,18 @@ # ramdisk: create or destroy a macOS APFS RAM disk + +declare -A rd_tags=( + TotalSize size + CapacityInUse 'in use' + APFSContainerFree free + DeviceNode device +) + +# extract and format plist values +plX () { + plutil -extract $1 raw - | nfmt | + awk '{print " → '"${rd_tags[$1]}"': " $1}' >&3 +} + ramdisk() { local cmd size blocks device backing mp="/Volumes/RAMDisk" @@ -71,15 +85,11 @@ ramdisk() { fi echo "→ RAMDisk mounted at $mp" - diskutil info -plist /Volumes/RAMDisk | tee \ - >(plutil -extract TotalSize raw - | nfmt | - awk '{print " → size: " $1}') \ - >(plutil -extract CapacityInUse raw - | nfmt | - awk '{print " → in use: " $1}') \ - >(plutil -extract APFSContainerFree raw - | nfmt | - awk '{print " → free: " $1}') \ - >(plutil -extract DeviceNode raw - | - awk '{print " → device: " $1}') > /dev/null + (diskutil info -plist /Volumes/RAMDisk | tee \ + >(plX TotalSize) \ + >(plX APFSContainerFree) \ + >(plX CapacityInUse) \ + >(plX DeviceNode) > /dev/null) 3>&1 | cat return 0 fi