Handy scripts you'd like to share


I had a bit of time to kill yesterday so I thought I'd write a minor script to correct something that was bothering me lately. Then I thought it might be a good opportunity to start up a permanent thread to share useful scripts members may have written.


So, I'll go first.


The following script is to prevent an external USB hard drive from sleeping.

This simple script will keep an external USB platter drive from spinning down and going to sleep. Some external USB drive enclosures do not respect the settings of sdparm, hdparm, or the system itself when it comes to setting a time threshold before an external drive is put to sleep. If a platter drive is put to sleep after a very short idle time it is not only inconvenient, but it can also contribute to premature drive wear. My enclosure was being put to sleep after only three minutes of inactivity, and because of a limitation of the drive's enclosure I could not alter this annoying behavior. This script simply creates a hidden file at a predetermined write interval, to prevent the drive being put to sleep. This may be very important to you if you want a drive to always be accessible for unattended backups etc. The script will keep executing indefinitely in a loop to prevent the drive from sleeping, (unless the user desires to discontinue it).

The same thing can also be accomplished with a cron job or a service. However, I think this method is more flexible, as this method can be started/stopped at any time by various methods. For example, if you'd like this script to start automatically, you can add the script to autostart in the "KDE System Settings". You can also easily start/stop the script anytime via a bash alias or a desktop file. This script also does not require root privileges, so any user can execute or terminate the script.

Follow the steps below to create the script to keep an external USB hard drive from going to sleep.

*Note:
You may need to substitute your username for $USER in the following commands.

First, create the scripts storage location:

mkdir -p /home/$USER/.local/bin

You can locate the script in an alternate location if you desire, as long as it does not require root privileges to access.

*Note:
You may need to substitute your username for $USER in the following commands.

With a text editor, create the keep_alive script:

/home/$USER/.local/bin/keep_alive.sh

With the following contents:

#!/bin/bash
# cat /home/$USER/.local/bin/keep_alive.sh
# Script to prevent a USB hard drive from sleeping
time=$(date +%Y-%m-%[email protected]%H:%M)
if [ "$EUID" -eq 0 ]; then
  echo "This script cannot be executed as root - exiting script"
  sleep 2
  exit 1
fi
   /usr/bin/touch /run/media/$USER/10TB-WD-2/.stayawake &> /dev/null
if  [ -f /run/media/$USER/10TB-WD-2/.stayawake ]; then
    echo -e "Drive last awakened @ $time" > /run/media/$USER/10TB-WD-2/.stayawake
fi
sleep 150
exec $0

Save the script, and then make the script executable:

chmod +x /home/$USER/.local/bin/keep_alive.sh

It is advisable, (but not 100% necessary) to give the drive a permanent mount location via /etc/fstab using the nofail option. The drive's name and path in the script /run/media/$USER/10TB-WD-2 must obviously be modified to reflect your intended drive's name and path. The time frame to write the file is set via the sleep value in seconds (sleep 150). If you wish the time interval in seconds to be longer or shorter, then alter the value from 150. The file's name .stayawake , is preceded with a dot, so that the file is hidden on your intended drive target. You may alter the name of the file if you desire as well. The hidden .stayawake file is automatically created by the script, and it also writes a timestamp to the file specifying when it was last written.


If you ever wish to terminate the keep_alive script, run:

killall -9 keep_alive.sh

If you want the script to run automatically, add the script to KDE's autostart at login in System Settings , (and then restart). You can also use a bash alias to easily start or stop the script from the terminal whenever you choose.


I also wrote two handy desktop files (with customized icons) so the script can be started or stopped from your taskbar/dock/desktop if you'd prefer to use that easy GUI method.

With a text editor, create the hd_awake.desktop file on your users desktop to start the script:

/home/$USER/Desktop/hd_awake.desktop

With the following contents:

[Desktop Action New]
Exec=/bin/bash -c "/home/$USER/.local/bin/keep_alive.sh"
Name=Prevent Hard Drive Sleep

[Desktop Entry]
Actions=New;
Categories=System;Utility;
Comment[en_CA]=Prevent Hard Drive Sleep
Comment=Prevent Hard Drive Sleep
Exec=/bin/bash -c "/home/htpc/.local/bin/keep_alive.sh"
GenericName[en_CA]=Prevent Hard Drive Sleep
GenericName=Prevent Hard Drive Sleep
Icon=gsmartcontrol
MimeType=
Name[en_CA]=Prevent Hard Drive Sleep
Name=Prevent Hard Drive Sleep
Path=/home/htpc/.local/bin/keep_alive.sh
StartupNotify=true
Terminal=false
TryExec=/home/htpc/.local/bin/keep_alive.sh
NoDisplay=true
Path=
StartupNotify=false
Type=Application
Version=1.0
X-DBUS-ServiceName=
X-DBUS-StartupType=
X-KDE-SubstituteUID=false
X-KDE-Username=

Save the desktop file, and then make it executable:

chmod +x /home/$USER/Desktop/hd_awake.desktop

With a text editor, create the hd_sleep.desktop file on your users desktop to stop the script:

/home/$USER/Desktop/hd_sleep.desktop

With the following contents:

[Desktop Action New]
Exec=/bin/bash -c "killall -9 keep_alive.sh"
Name=Allow Hard  Drive Sleep

[Desktop Entry]
Actions=New;
Categories=System;Utility;
Comment[en_CA]=Allow Hard  Drive Sleep
Comment=Allow Hard  Drive Sleep
Exec=/bin/bash -c "killall -9 keep_alive.sh"
GenericName[en_CA]=Allow Hard  Drive Sleep
GenericName=Allow Hard  Drive Sleep
Icon=gnome-disks-state-standby-symbolic
MimeType=
Name[en_CA]=Allow Hard  Drive Sleep
Name=Allow Hard  Drive Sleep
StartupNotify=true
Terminal=false
NoDisplay=true
Path=
StartupNotify=false
Type=Application
Version=1.0
X-DBUS-ServiceName=
X-DBUS-StartupType=
X-KDE-SubstituteUID=false
X-KDE-Username=

Save the desktop file, and then make it executable.

chmod +x /home/$USER/Desktop/hd_sleep.desktop

After the desktop files are created you can then drag and drop them onto your taskbar/dock or your desktop for easy execution. Below is a screenshot of the "Awake" and "Sleep" buttons (created with the .desktop files) to the right of the Garuda logo (top left of taskbar).

If the icons I've chosen in the desktop file are not available on your system, then you will need to edit the Icon= line in the desktop file and choose an alternate icon.

Well that's about it. I hope my simple script helps someone.


Hopefully others will use this thread to share their scripting efforts as well. Feel free to add whatever scripts you've written so that other forum users can benefit and gain scripting knowledge.


12 Likes

This is a nice script to use instead of ever having to git add or git commit

───────┬─────────────────────────────────────────────────────────────────────────────────────
       │ File: commit
───────┼─────────────────────────────────────────────────────────────────────────────────────
   1   │ #!/bin/sh
   2   │ git add -u
   3   │ git diff HEAD
   4   │ git status -uno
   5   │ printf "Commit these files? [commit message, or blank to cancel]\n > " | lolcat
   6   │ read commitmsg
   7   │ [ -z "$commitmsg" ] && exit 1
   8   │ git commit -m "$commitmsg"
───────┴─────────────────────────────────────────────────────────────────────────────────────

This script lets you take multiple pdf files and outputs another pdf file appended. For example, if I have 1.pdf and 2.pdf then pdfcat 1.pdf 2.pdf will output (to stdout) another pdf with all the pages from 1.pdf then all the pages from 2.pdf. It's been useful a couple of times.

───────┬─────────────────────────────────────────────────────────────────────────────────────
       │ File: pdfcat
───────┼─────────────────────────────────────────────────────────────────────────────────────
   1   │ #!/bin/sh
   2   │ gs -dBATCH -dNOPAUSE -sDEVICE=pdfwrite -sOutputFile=- -f "[email protected]"
───────┴─────────────────────────────────────────────────────────────────────────────────────

This prints size information for all the files and directories in your working directory. I suppose I could update it to use exa, but its fine for now.

───────┬─────────────────────────────────────────────────────────────────────────────────────
       │ File: mydu
───────┼─────────────────────────────────────────────────────────────────────────────────────
   1   │ #!/bin/sh
   2   │ du -hd 1 --exclude=/proc* "[email protected]" 2>/dev/null | sort -h | lolcat
   3   │ ls -laFh "[email protected]" | sed '/^d/d;/^total/d' | awk '{print $5 "\t" $9}' | sort -hr
───────┴─────────────────────────────────────────────────────────────────────────────────────

I ilke to convert videos and audio to webms with ffmpeg to save space.

───────┬─────────────────────────────────────────────────────────────────────────────────────
       │ File: webmify
───────┼─────────────────────────────────────────────────────────────────────────────────────
   1   │ #!/bin/sh
   2   │ 
   3   │ name="$(echo $1 | cut -f1 -d'.')"
   4   │ ffmpeg -i "$1" "$name"'.webm' -loglevel warning -stats
───────┴─────────────────────────────────────────────────────────────────────────────────────

I have a few more at GitHub - magnus-ISU/usrlocalbin: Small scripts I've written that aren't worth putting in the AUR but these are the most useful and some of the ones there aren't really useful at all on KDE, I made them when I used vanilla arch with dmenu.

The coolest is sms I guess, which lets you send text messages through KDE connect on the command line.

6 Likes

Thought I'd play with my PS1 prompt today. I haven't played with it in a long time so I was pretty rusty.

Here's my simple PS1 prompt script:

if [[ ${EUID} == 0 ]] ; then
		PS1='\[\033[01;31m\]\[email protected]\h\[\033[0;33m\]: \w\[\033[01;31m \n\[\033[1;33m\]\$'
#  ROOT PS1:   [email protected]$HOST  -  "RED"  ===  FULL PATH - "ORANGE"  ===  PROMPT & FONT  -  "YELLOW"   ===  CURSOR  -  "RED"
else
		PS1='\[\033[0;34m\]\[email protected]\h\[\033[0;34m\]:\[\033[0;00m\] \w \n\d \[\033[0;34m\]\@ \n\[\033[0;0m\]\$'
#  USER PS1:   [email protected]$HOST  - "BLUE"  ===  FULL PATH  -  "DEFAULT"  ===  $DATE  -  "DEFAULT"  ===  $TIME  - "BLUE"  === $ - "DEFAULT COLOR"  			
fi

Just in case anyone else likes playing with that kind of thing.

3 Likes

simple script to check for IOMMU groups

#!/bin/bash
shopt -s nullglob
for g in /sys/kernel/iommu_groups/*; do
    echo "IOMMU Group ${g##*/}:"
    for d in $g/devices/*; do
        echo -e "\t$(lspci -nns ${d##*/})"
    done;
done;

2 Likes

I've been exploring a freeze bug which can occur up to 2 weeks from launch. This script gives me the elapsed time from launch to freeze. Thanks to tbg for an example with exec $0 which is just cleaner looking than an infinite loop!

#!/bin/bash
# ./stats.sh
# First time only, show launch time and kernel version
if [ $# -eq 0 ]
then
  echo " "`date +%D" "%H:%M`" "`uname -svr`
fi

# update run time without scrolling the terminal screen 
printf " %s" `date +%D" "%H:%M` `uptime -p`
# erase any trailing characters leftover from last update
printf "       \r"
sleep 60
# relaunch script with one argument to suppress launch time echo
exec $0 1

My original script ran once and had to be manually run to update. This new script might affect my experiment if my freeze is related to inactivity... edit: it still froze.

Update: great idea until I guessed that the command line would grow each iteration. Maybe a simple loop is safer after all! The argument "1" is saved to $1 and not appended to $0.

2 Likes

I have a thing about notifiers - when I want to know something, I want to know it NOW. So - I have a couple of ways of avoiding notifiers on my setups. One of them is a conky setup that constantly displays counts of packages needing updates, along with a vertically scrolling list of what they are and what versions they will be.

The other is a couple of bash functions (which could be scripts easily enough) which I leave in my .bashrc file. One of them displays the names and versions of all packages (repo and AUR) - formatted and displayed, and the other just provides counts. If anyone else likes the info 'on demand' here they are:

Bash functions
upls() {
# create vars
NEWAUR=0

# count AUR updates
NEWAUR=`yay -Qua | wc -l`

# run checkupdates to create file in /tmp
		echo "Repo Packages" > /tmp/update-list
		echo "-------------" >> /tmp/update-list
checkupdates | column -t -N Name,Current,"->",New >> /tmp/update-list
if [[ ${NEWAUR} > 0 ]]; then
		echo " " >> /tmp/update-list
		echo "AUR Packages" >> /tmp/update-list
		echo "------------" >> /tmp/update-list
		yay -Qua | column -t -N Name,Current,"->",New >> /tmp/update-list
fi

# output RESULT
if [[ -s /tmp/update-list ]]; then
	cat /tmp/update-list
	rm /tmp/update-list
else
	echo "No pending updates..."
fi
}

# Function to count available updates

upcnt() {
# create vars
NEWPKG=0
NEWAUR=0

# count AUR and pacman updates
NEWAUR=`yay -Qua | wc -l`
NEWPKG=`checkupdates | wc -l`

# output RESULT
if [[ ${NEWPKG} == 0 && ${NEWAUR} == 0 ]]; then
	RESULT="System up-to-date"
else
	RESULT=$NEWPKG" Repo pkgs + "$NEWAUR" AUR pkgs need updating"
fi
echo $RESULT
}


#------------------------------------------------------------

This text will be hidden

No warranty on them having style points - but they DO work, and safely...

3 Likes

Some helping stuff here, just in case you find it interesting: https://www.kernel.org/doc/Documentation/usb/power-management.txt

EDIT: to make it smaller, and ... there is a USB autosuspend param in the kernel, maybe replacing the "usb disk keep alive" script ?
EDIT: nevermind.... my lack of basic reading skills made me make an ass out of myself! SORRY!

Gpu set max wattage usage ( i am on amd card ):

#!/bin/bash

DEVICE=$(find /sys/devices -name power1_cap)
WATT=50

if [ $# -eq 1 ]; then
    WATT=${1}
fi

echo ${WATT}000000 > $DEVICE

echo "auto" > /sys/class/drm/card0/device/power_dpm_force_performance_level

Because backups make life boring, snapper deleter!:

#!/bin/sh

for x in $(ls /etc/snapper/configs/) ;
do
    RANGE=$(snapper -c $x list | tail -n1 | cut -d" " -f1)
    if [ $RANGE -gt 0 ]; then
        echo Deleting snapshots in $x
        snapper -c $x delete 0-$RANGE
    else
        echo Nothing to delete in $x
    fi
done