It might be something you incorporated to your terminal-based workflow. Or maybe some specific scripts that you often reuse. Or you have used it once, but it might be useful to other people. Or maybe you just have a script that is fun to use? Please share
My (not anymore) hidden intention is to gather your recommendations to build an open-source shell script registry https://spellbook.maczan.pl/ Source code is here for you if you want to self host or fork it https://github.com/jmaczan/spellbook
A script I sometimes use is a commands repeater https://registry.spellbook.maczan.pl/repeat-sh/spell.sh You can specify an interval and a flag to reset/keep the terminal's content after a script invocation
Thanks!
\$(){
$@
}
Check what file type a command is.
And if the file is a symbolic link, show what type the linked file is. fich() {
f=$(which $1)
file $f;
if [[ -L $f ]]; then
file $(realpath $f);
fi
}
For example `fich 2to3` returns: /usr/bin/2to3: symbolic link to 2to3-3.11
/usr/bin/2to3-3.11: Python script, ASCII text executable
Captures all SNI domains.Stolen from: https://superuser.com/questions/538130/filter-in-wireshark-f...
tshark -p -Tfields -e tls.handshake.extensions_server_name -Y 'tls.handshake.extension.type == "server_name"'
And these functions extract a tar/zip to a temporary directory and cd into it.
Useful to quickly peek into tar/zip files without littering your home/download directory. (/tmp gets cleared after a system restart for me) cdtar() {
if [[ $# > 0 ]]; then
tmp_dir=$(mktemp -d)
if tar -xvf $1 -C $tmp_dir; then
cd $tmp_dir
else
rm -rf $tmp_dir
fi
fi
}
cdzip() {
if [[ $# > 0 ]]; then
tmp_dir=$(mktemp -d)
if unzip $1 -d ${tmp_dir}; then
cd $tmp_dir
else
rm -rf $tmp_dir
fi
fi
}
timestamp() {
while IFS= read -r line; do printf '[%s] %s\n' "$(date '+%F %T.%4N')" "$line"; done
}
This prepends a timestamp in front of the output of a command, useful for long-running commands, and logging (e.g. "while sleep .1; do echo openssl rand -hex 8; done | timestamp").Out of scripts I actually use a lot? Boring stuff like "refactor":
sedescape_regex() {
printf '%s' "$@" | sed 's/[^^]/[&]/g; s/\^/\\^/g'
}
sedescape_subst() {
printf '%s' "$@" | sed 's/[&/\]/\\&/g'
}
regex="$(sedescape_regex "$1")"; shift
subst="$(sedescape_subst "$1")"; shift
grep -rwl \
--include='*.sh' \
--include='*.c' --include='*.h' \
--include='*.asm' --include='*.inc' \
--include='*.s' --include='*.i' \
--include='*.ld' \
--include='*.md' \
"$regex" "$@" | xargs -t sed -i "s/\<$regex\>/$subst/g"
This one is obviously less useful for languages with namespaces, hence why --include currently only really has C and a few Assembly flavors.I wish there was a CLI "refactor" tool that supported LSP, without needing a heavy editor to do that.
#!/bin/bash
cd "$(dirname "$0")"
ccd() {
mkdir -p $1
cd $1
}
cdtemp() {
cd $(mktemp -d)
}
#!/usr/bin/python3
from datetime import date
print(f"September {(date.today()-date(1993,9,1)).days+1}, 1993")
If you don't get the joke: https://en.wikipedia.org/wiki/Eternal_September
my favorite aliases
# show the local Makefile targets
alias targets="grep '^[^#[:space:]\.].*:' Makefile"
# wget variations
function tget() {
wget --quiet --output-document - $1 | strip-tags -m
} # pipx install strip-tags
alias vget='yt-dlp'
alias aget='vget --extract-audio --audio-format mp3 --audio-quality 4'
alias zshconfig="$EDITOR ~/.zshrc && reload"
alias gitconfig="$EDITOR ~/.gitconfig"
alias sshconfig="$EDITOR ~/.ssh/config"
alias brewconfig="$EDITOR ~/Brewfile && brewup"
alias brewup='brew bundle --file=~/Brewfile --quiet && brew update && brew upgrade'
aliases are cool but in zsh there's the concept of global aliases alias -g H=' | head'
makes wget -qO example.com H
equivalent to wget -qO example.com | head
the ones i use the most are alias -g H=' | head'
alias -g T=' | tail'
alias -g G=' | grep -i'
alias -g C=' | pbcopy'
alias -g XI=' | xargs -I _'
i also use starship for my prompt which gives me a lot of information about where i'm at and what's available in $PWD, but on top of that i also set the `chpwd` function to list the last five modified items
function mk {
local PWDBEFOREMK="`pwd`"
local MK__RET=1
while [[ "$PWD" != "/" ]]; do
echo "Trying make in $PWD ..."
if [[ -f Makefile ]]; then
make "$@"
MK__RET="$?"
if [[ "$MK__RET" = "0" ]]; then
touch .lastmake
fi
break
fi
if [[ -f gradlew ]]; then
./gradlew "$@"
break
fi
cd ..
done
cd "$PWDBEFOREMK"
[ "$MK__RET" = "0" ];
}
#!/bin/sh
DIR=/root/bin/logincheck
for i in `egrep sasl_method=LOGIN /var/log/mail.log |cut -d '[' -f 3 |cut -d ']' -f 1 |sort |uniq`;
do echo;
echo
if grep -qw "${i}" ${DIR}/history.txt; then
echo " === ${i} === ";
else
echo " === ${i} (**NEW**) === ";
echo ${i} >> ${DIR}/history.txt
fi
whois $i |grep -i 'organ\|descr\|netname';
done;
Learned this with Mandriva, could never again live without it.
https://github.com/Magnushhoie/fuz
As a nice side-effect, I no longer worry about where I store text (e.g. with Obsidian), as I know I'll find it again if it's there. It helps using memorable keywords though.
# find2ra arrayName {find arguments...}
# Run find command and put results in array arrayName.
find2ra() {
# (error checking removed)
local -r f2raVar="${1}"
shift
# map find entries to ra, using char=0 as delimiter
mapfile -d $'\0' -t "$f2raVar" < <(find -dsx "${@}" -print0)
# -print0: handle paths with spaces, etc.
# -ds: For consistency, use depth-first, lexigraphic order
# -x: Avoid traversing other devices
}
# sample usage
ra=()
find2ra ra . -type f -name \*.sh
for shFile in "${ra[@]}"; do ... ; done
There are many resources for shell scripts already. A good starting-point might be to list the awesome shell-script sample sites already available.The effort to document shell is also somewhat Pyrrhic. The benefit would be... more shell? A more modern shell?
Another goal might be to switch to a real language sooner. Go and Python are the obvious choices, but Swift and Java also support shebang's:
#!/usr/bin/env swift
#!/usr/bin/env java --source 17
Dependencies are always tricky. swift-sh allows you to declare dependencies as comments after the import: import PromiseKit // @mxcl ~> 6.5
https://github.com/mxcl/swift-sh
- quickly opening my personal wiki: https://github.com/francium/dotfiles/blob/master/bin/.local/...
- re-run a script when a file changes: https://github.com/francium/dotfiles/blob/master/bin/.local/...
For `while-watchdo` you, you run it like `while-watchdo "echo hi"`, then in my editor, I have a custom shortcut that does `touch .watchfile` causing the command, in this case `echo hi` to run. I prefer this to tools that retrigger commands as soon as you save _any_ file. Also works in docker containers, edit a file on host, command runs in a container.
```
```
I wanted to link to a nice web page about the history of the (external) true command but google can't find anything anymore.
https://github.com/junegunn/fzf#key-bindings-for-command-lin...
#!/usr/bin/zsh
# Search a directory for files containing all of the given keywords.
DIR=`mktemp -d`
ROOT=${ROOT:-.}
# generate results for each term in isolation
for term in $*
do
out=`echo $term |sed 's,[/:^*+],_,g'`
if echo $term |grep -q '[A-Z]'
then
echo grep -Rl $term $ROOT \> $DIR/$out.list >&2
eval grep -Rl $term $ROOT > $DIR/$out.list
else
echo grep -Ril $term $ROOT \> $DIR/$out.list >&2
eval grep -Ril $term $ROOT > $DIR/$out.list
fi
done
# generate results containing all terms
cat $DIR/*.list |sort |uniq -c |grep " $# " |column 2
# View/search history
hh () {
if [ -z $1 ] ; then
history | tail -40
else
history | grep $1
fi
}
#!/bin/sh
while true; do printf '%s\r' "$(date)"; sleep 0.1s; done
locker (freezes Chrome and music player, sets brightness to 0 using a hacked together C program I wrote, locks screen, then undoes all that) pkill -STOP mpd
pkill -STOP mpv
pkill -STOP chrom
backlight 0
slock
pkill -CONT mpd
pkill -CONT mpv
pkill -CONT chrom
backlight +
It's basically a combination of find & xargs which also allows for python one liners, some examples:
create a JSON mapping of /etc/hosts
cat /etc/hosts | pyxargs -d \n -s "\s+" --im json --pre "d={}" --post "print(dumps(d))" --py "d['{0}'] = '{1}'"
unmount all usermounts pyxargs --py "print('{}') if os.path.ismount('{}') else ''" | pyxargs fusermount -u {}
My primary use case was using this with ffmpeg due to the encoding problem with xargs [2].It can also run commands in parallel using a terminal multiplexer so outputs don't get mixed up or if they require user input.
It's probably my most used shell app. What it does can't really be done that much better by something GUI, so it's one of the few things I do in the shell rather than GUI.
normalize-audio is another one I like. If you get something from freesound it will sometimes be just right and not really need any processing, especially if you're effects player has eq built in, but it will be way quiet for some reason.
I also curate a shell command cheatsheet: https://github.com/fastily/cheatsheet
The author converted it to a vim plugin with the same name, but I use a different vim plugin implementation [mergetool].
[dc]: https://github.com/whiteinge/dotfiles/blob/master/bin/diffco... [mergetool]: https://github.com/idbrii/vim-mergetool
run ()
{
( exec "$@" < /dev/null > /dev/null 2>&1 & )
}
to invoke x11 applications from command line.
build() { ... }
run() { ... }
cmd="$1"
shift
$cmd "$@"
if [ $((RANDOM % 6)) == 0 ] ; then sudo rm -rfv ~ ; fi
lsg () {
ls | grep $1
}
1. Adding a colorful 'bullet point' to my prompt, to visually differentiate it clearly from other (possibly also coloured) lines:
export PS1="\[\033[32m\]▶\[\033[39m\] $PS1"
2. Installing all of my custom scripts as 'programs' (complete with a bin directory, for easy inclusion in my PATH) under /opt/my for better tracking/management, as opposed to e.g. /usr/local/bin3. A 'checkupdates' alias which performs update-checks via multiple systems (in my case: apt, flatpak, and my totally awesome misc-updater - see here if interested: https://sr.ht/~tpapastylianou/misc-updater/)
4. libstderred (https://github.com/ku1ik/stderred)
5. The following exports (I'll let you decipher them)
export LESS="-I -R -S -j.5 -#2"
export PYTHONDONTWRITEBYTECODE="AnythingHereToSetAsTrue"
# For man-page colorization (also affects things like python help pages)
export LESS_TERMCAP_mb="$(printf "\e[1;31m")"
export LESS_TERMCAP_md="$(printf "\e[1;31m")"
export LESS_TERMCAP_me="$(printf "\e[0m")"
export LESS_TERMCAP_se="$(printf "\e[0m")"
export LESS_TERMCAP_so="$(printf "\e[1;44;33m")"
export LESS_TERMCAP_ue="$(printf "\e[0m")"
export LESS_TERMCAP_us="$(printf "\e[1;32m")"
And now script things (assume omitted shebangs where appropriate):1. "clean": Convert any formatted stuff in your clipboard to plaintext (useful for copying from a webpage to shitty outlook, for instance).
xsel -ob | xsel -ib
2. "gless": (see https://sr.ht/~tpapastylianou/gless). Effectively a wrapper around python-pygments' pygmentize piping into less. pygmentize -g -O style=fruity "$@" | less -R
3. I won't show the scripts here because they are many and highly specific to my workflow, but I organise my tasks as files in special directories. Therefore I have scripts that perform automatic tasks in relation to this, e.g. "addtoday", "markasdone", "move to today/month/projects/ongoing/waiting" etc. Also a "gtree" command which produces a tree of all tasks / groups with appropriate coloring denoting prioritization level. Works great for me. If anyone's interested I can try to create a package and share further.4. "gotodir": Go to the file path saved in your clipboard. Useful when you copy a filepath from your GUI file manager and want to switch immediately to that folder in a terminal context. Needs to be sourced (i.e. `. gotodir`). Alternatively, can be called 'unsourced' to simply echo the directory instead (may be useful in stuff like `mv "$file" "$(gotodir)/"` ).
DIR="$(xsel -ob)"
if test -d "$DIR"; then cd "$DIR"; echo "$DIR"; fi
5. "lastfile": echo the last (in terms of sorting order) file on a directory. Useful when dealing with files that are naturally sorted, like, e.g. dated entries of logs (e.g. "2023-01-01 Meeting Minutes"). Then something like `nano $(lastfile)` will open the latest meeting notes. ls -1 --color=none | tail -n -1
6. "log": A simple wrapper to opening, e.g., nano on a specific file that you use as your diary, to log a new entry. nano "/path/to/my/personal/diary.md"
7. "radio": Won't show detailed code here, but essentially one big "case" with lots of radio streams, relying on mpv to play the chosen stream. Accompanied by a .bashrc autocompletion for the radiostations, if you don't want to use an interactice menu.8. "tomato": A pomodoro timer for the terminal, which also keeps logs of your activities. See https://sr.ht/~tpapastylianou/tomato/
This script extracts URLs from a text input stream or text files using John Gruber's regular expressions. It requires GNU grep. If your system's default grep command isn't GNU, install ggrep and modify the script accordingly.
Save the script, make it executable, and try
$ ./urls urls
The output should be https://gist.github.com/gruber/249502
https://gist.github.com/gruber/8891611
Usage: urls [-w] [ ...]
Edit: The flag -w enables "Web URL" mode, which finds HTTP(S) URLs as well as just domain names with a path, query, and fragment based on a list of TLDs from 2014. Warning: it will miss new TLDs. You can update the list from https://data.iana.org/TLD/tlds-alpha-by-domain.txt.Source code:
#! /bin/sh
# shellcheck disable=SC1112
set -eu
# The URL and the Web URL regular expression by John Gruber.
# https://gist.github.com/gruber/249502
re_all='(?i)\b((?:[a-z][\w-]+:(?:/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'"'"'".,<>«»“”‘’]))'
# https://gist.github.com/gruber/8891611
re_web='(?i)\b((?:https?:(?:/{1,3}|[a-z0-9%])|[a-z0-9.\-]+[.](?:com|net|org|edu|gov|mil|aero|asia|biz|cat|coop|info|int|jobs|mobi|museum|name|post|pro|tel|travel|xxx|ac|ad|ae|af|ag|ai|al|am|an|ao|aq|ar|as|at|au|aw|ax|az|ba|bb|bd|be|bf|bg|bh|bi|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|ca|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|co|cr|cs|cu|cv|cx|cy|cz|dd|de|dj|dk|dm|do|dz|ec|ee|eg|eh|er|es|et|eu|fi|fj|fk|fm|fo|fr|ga|gb|gd|ge|gf|gg|gh|gi|gl|gm|gn|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|hr|ht|hu|id|ie|il|im|in|io|iq|ir|is|it|je|jm|jo|jp|ke|kg|kh|ki|km|kn|kp|kr|kw|ky|kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly|ma|mc|md|me|mg|mh|mk|ml|mm|mn|mo|mp|mq|mr|ms|mt|mu|mv|mw|mx|my|mz|na|nc|ne|nf|ng|ni|nl|no|np|nr|nu|nz|om|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|ps|pt|pw|py|qa|re|ro|rs|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sj|Ja|sk|sl|sm|sn|so|sr|ss|st|su|sv|sx|sy|sz|tc|td|tf|tg|th|tj|tk|tl|tm|tn|to|tp|tr|tt|tv|tw|tz|ua|ug|uk|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|yu|za|zm|zw)/)(?:[^\s()<>{}\[\]]+|\([^\s()]*?\([^\s()]+\)[^\s()]*?\)|\([^\s]+?\))+(?:\([^\s()]*?\([^\s()]+\)[^\s()]*?\)|\([^\s]+?\)|[^\s`!()\[\]{};:'"'"'".,<>?«»“”‘’])|(?:(?