По роду деятельности мне часто приходится подключать жёсткие диски к своему компьютеру через SATA разъём. После некоторых манипуляций с ними я обычно просто выдёргиваю питание и шлейф из разъёмов. Но каждый раз при этом диск в моих руках немного витает в воздухе. А шпиндель-то в это время ещё не остановился — что может привести к физическим повреждениям диска и потере данных.
И каждый раз я думал что вот-вот сяду и напишу скрипт для отключения питания, а потом уже буду отключать винт физически.
И вот, наконец, у меня появилось достаточно времени чтобы сесть и спокойно этим заняться.
Google честно признался, что проще всего это сделать отправив единичку в «/sys/block/sdx/device/delete». Когда же подключено несколько дисков, неудобно запоминать букву каждого и менять её в строке. А какой диск мне нужно отключить проще опознать по его названию, размеру и разделам на нём. И вот, после нескольких весёлых часов отладки и разных улучшений, у меня получился маленький скрипт:
sataStop.sh
#!/bin/bash
# - - - - - - - - - - - - - - = = = = = = = - - - - - - - - - - - - - -
Name="SATA Stop"
# Desc: Turns off SATA drives
# Usage: sudo sh ./sataStop.sh
#
# Author: Samolysov Maxim
# E-mail: zBestR@bk.ru
# License: Free for all with NO guarantee. Just think & make sure you know what R`You doing
# - - - - - - - - - - - - - - = = = = = = = - - - - - - - - - - - - - -
# HISTORY
Version="01.00.01"; Date=[21.04.2013]
# + basic functionality
# + colors
# + once I`ve stopped ROOT disk... (just for sure it works)... So, now here is a check to not let this happens again )))
#
Version="01.00.02"; Date=[24.04.2013]
# ! fixed bug with last disk skipped (not turned off)
Version="01.00.03"; Date=[07.05.2013]
# + colorized X-letter in sdX
Version="01.00.04"; Date=[10.05.2013]
# + getSize function
# + show disk size in GB & GiB
# in future... Version="01.00.0"; Date=[..2013]
# + try to unmount mounted partitions (use with care)
# HISTORY END
# - - - - - - - - - - - - - - = = = = = = = - - - - - - - - - - - - - -
### GLOBAL VARIABLES
disks=$(ls /sys/block/ | grep sd)
count=0
ROOT_DISK=""
HAS_MOUNTS=""
SIZE=""
# Regular Colors
Black='\e[01;30m' # Black
Red='\e[00;31m' # Red
LightRed='\e[01;31m' # LightRed
Green='\e[00;32m' # Green
LightGreen='\e[01;32m' # LightGreen
Yellow='\e[00;33m' # Yellow
LightYellow='\e[01;33m' # LightYellow
Blue='\e[00;34m' # Blue
LightBlue='\e[01;34m' # LightBlue
Purple='\e[00;35m' # Purple
LightPurple='\e[01;35m' # LightPurple
Cyan='\e[00;36m' # Cyan
White='\e[01;37m' # White
Color_Off='\e[0m' # Reset color
fullName=" $LightYellow$Name$Yellow v.$LightBlue$Version $Yellow$Green$Date$Yellow"
### GLOBAL VARIABLES END
### - - - - - - - - - - - - - - = = = = = = = - - - - - - - - - - - - - - = = = = = = = - - - - - - - - - - - - - -
##### FUNCTIONS
checkMounted () {
mountedTo=$(sudo lsblk -ro name,mountpoint $1 | grep $1 | awk '{print $2}')
} # checkMounted END
getModel () {
model=$(sudo hdparm -i /dev/$1 | grep -i model| sed -e 's/Model=/\"/' -e 's/,.*$/\"/')
} # getModel END
getSize () {
SIZE=""
# local size=$(sudo lsblk -ro size /dev/$disk | awk 'NR == 2 {print ($1)}' | sed 's/,/./')
local device=$1
local bi=$2
local sp=""
local bsize=$(cat /sys/block/$device/size)
bsize=$( expr $bsize '*' 512)
if [[ $bsize -lt 1000 ]]; then
bsize="$bsize"
sp="B"
elif [[ $bsize -lt 1000000 ]]; then
[[ $bi = 1 ]] && bsize="$bsize/1024" sp="KiB" || bsize="$bsize/1000" sp="KB"
# sp="KB"
elif [[ $bsize -lt 1000000000 ]]; then
[[ $bi = 1 ]] && bsize="$bsize/1048576" sp="MiB" || bsize="$bsize/1000000" sp="MB"
# bsize="$bsize/1048576"
# sp="MB"
else
[[ $bi = 1 ]] && bsize="$bsize/1073741824" sp="GiB" || bsize="$bsize/1000000000" sp="GB"
# bsize="$bsize/1073741824"
# sp="GB"
fi
bsize=$(echo "scale=0; $bsize" | bc -l)
[[ $bsize -lt 10 ]] && bsize=" $bsize"
[[ $bsize -lt 100 ]] && bsize=" $bsize"
[[ $bsize -lt 1000 ]] && bsize=" $bsize"
SIZE="$bsize $sp"
} # getSize END
main () {
echo -e "$fullName"
# !!! Do NOT even FUCKING try to TURN OFF the ROOT disk !!! COMPUTER WILL FRIZE AND POSSIBLY LOST DATA !!!
for disk in $disks; do
let count++
echo -ne "$Red"
local model=$(sudo hdparm -i /dev/$disk | grep -i model| sed -e 's/Model=/\"/' -e 's/,.*$/\"/')
getSize "$disk" 0
local size="$SIZE"
getSize "$disk" 1
local size="$size ($SIZE)"
disk_1="sd"
disk_2=$(echo $disk | sed 's/..//')
echo -e "$LightYellow$count. $LightPurple$disk_1$LightYellow$disk_2\t\e[07;32m$size\e[0m\t$LightGreen$model$ColorOff"
local parts=$(sudo lsblk -ro name,type | grep $disk | awk '/part/ {print ($1)}' )
for part in $parts; do
local mountedTo=$(sudo lsblk -ro name,mountpoint /dev/$part | grep $part | awk '{print $2}')
local fileSystem=$(sudo lsblk -ro name,fstype /dev/$part | grep $part | awk '{print $2}')
getSize "$disk/$part" 1
fileSystem="\t$fileSystem\t $SIZE"
if [[ $mountedTo == "" ]]; then
mountedTo="$Green\tnot mounted $ColorOff"
elif [[ $mountedTo == "/" ]]; then
# !!! Do NOT even FUCKING try to TURN OFF the ROOT disk !!! COMPUTER WILL FRIZE AND POSSIBLY LOST DATA !!!
ROOT_DISK=$count
mountedTo="$Red\t$mountedTo$Yellow\t<--- this is$Red ROOT$ColorOff"
elif [[ $mountedTo == "[SWAP]" ]]; then
mountedTo="$Red\t$mountedTo$ColorOff"
else
HAS_MOUNTS="$HAS_MOUNTS $disk"
mountedTo="$LightBlue\t$mountedTo$ColorOff"
fi
echo -e " $Yellow$part$fileSystem$mountedTo$ColorOff"
done
done # disk in $disks
echo -ne "$LightPurple\rEnter disk number [$LightYellow 1-$count $LightPurple] to turn off ($LightYellow \"Enter\" to exit $LightPurple):$ColorOff $LightYellow"
read answer
# !!! Do NOT even FUCKING try to TURN OFF the ROOT disk !!! COMPUTER WILL FRIZE AND POSSIBLY LOST DATA !!!
if [[ $answer == $ROOT_DISK ]]; then
echo -e "$Red Do You$LightRed REALLY$Red believe I\`ll stop disk with $LightRed\"ROOT\"$Yellow ??? $LightGreen Sorry, Bro$Yellow...\n $LightBlue I\`m a clever script $Yellow)))$LightPurple But You can still trying$Yellow..."
sleep 15
else
if [[ $count+1 > $answer && $answer > 0 ]]; then
stop_disk=$(echo ${disks} | awk '{print $'$answer'}')
local disk_mounted="no"
d_isk_number=$(echo ${HAS_MOUNTS} | grep -q "${stop_disk}") && disk_mounted="yes"
if [[ $disk_mounted == "yes" ]]; then
echo -e "$LightPurple$stop_disk$LightBlue has mounted partitions.$Yellow Unmount them and try again."
sleep 15
else
local model=$(sudo hdparm -i /dev/$stop_disk | grep -i model| sed -e 's/Model=/\"/' -e 's/,.*$/\"/')
echo -ne "Turning off $LightPurple$stop_disk $LightGreen$model... "
sudo sh -c "echo 1 > /sys/block/$stop_disk/device/delete"
sleep 2
# !!! Do NOT even FUCKING try to TURN OFF the ROOT disk !!! COMPUTER WILL FRIZE AND POSSIBLY LOST DATA !!!
ls /sys/block | grep -q "${stop_disk}" || echo -e "$LightYellow Successfully stopped."
sleep 15
fi
fi
fi # $answer == $ROOT_DISK
echo -e "$LightYellow Exit."
sleep 3
} # main END
##### FUNCTIONS END
### - - - - - - - - - - - - - - = = = = = = = - - - - - - - - - - - - - - = = = = = = = - - - - - - - - - - - - - -
##### START SCRIPT
clear
main
echo -ne "$ColorOff"
##### START SCRIPT END
с удобным выводом:

Теперь можно смело выдёргивать шлейф из диска ведь шпинделю хватает времени остановиться (1-3 секунды) пока мои руки дотронутся до самого диска.
P.S. Если мой скрипт спасёт хоть несколько дисков и убережёт чьи-то данные от потери, я считаю задачу выполненной.