This is part of the Zsh Utilities.
This file provides several functions for very different use. See the description to understand the aim of each of them.
This part defines some function in relation with package management. It defines generic function name given the linux system installed : “debian-like” system or archlinux.
function __is_debian ()
{
if pkgtools::has_binary apt-fast; then
__pkg_mgr="apt-fast"
return 0
elif pkgtools::has_binary apt; then
__pkg_mgr="apt"
return 0
elif pkgtools::has_binary apt-get; then
__pkg_mgr="apt-get"
return 0
elif pkgtools::has_binary yaourt; then
__pkg_mgr="yaourt"
return 1
elif pkgtools::has_binary pacman; then
__pkg_mgr="pacman"
return 1
fi
}
alias pkg-notify='--notify -t 2000 -i gtk-info "${__pkg_mgr}"'
if __is_debian; then
function install ()
{
pkgtools::at_function_enter install
sudo ${__pkg_mgr} install -y $* && pkg-notify "Installed $@"
pkgtools::at_function_exit
return 0
}
compdef "_deb_packages uninstalled" install
function remove ()
{
pkgtools::at_function_enter remove
sudo ${__pkg_mgr} remove -y $* && pkg-notify "Removed $@"
pkgtools::at_function_exit
return 0
}
compdef "_deb_packages installed" remove
function upgrade ()
{
pkgtools::at_function_enter upgrade
sudo ${__pkg_mgr} update && sudo ${__pkg_mgr} -y upgrade && pkg-notify "Upgrade done"
pkgtools::at_function_exit
return 0
}
function search ()
{
pkgtools::at_function_enter search
apt-cache search $@
pkgtools::at_function_exit
return 0
}
function purge ()
{
pkgtools::at_function_enter purge
sudo ${__pkg_mgr} purge && pkg-notify "Purge done"
pkgtools::at_function_exit
return 0
}
function distupgrade ()
{
pkgtools::at_function_enter distupgrade
sudo ${__pkg_mgr} update && sudo ${__pkg_mgr} dist-upgrade && pkg-notify "Distribution upgrade done"
pkgtools::at_function_exit
return 0
}
function autoremove ()
{
pkgtools::at_function_enter autoremove
sudo ${__pkg_mgr} autoremove && pkg-notify "Autoremove done"
pkgtools::at_function_exit
return 0
}
else
function upgrade ()
{
pkgtools::at_function_enter upgrade
${__pkg_mgr} -Suy --noconfirm && pkg-notify "Upgrade done"
pkgtools::at_function_exit
return 0
}
function upgrade-aur ()
{
pkgtools::at_function_enter upgrade-aur
${__pkg_mgr} -Suya --devel --noconfirm && pkg-notify "Upgrade done"
pkgtools::at_function_exit
return 0
}
function search ()
{
pkgtools::at_function_enter search
${__pkg_mgr} -Ss $@
pkgtools::at_function_exit
return 0
}
function purge ()
{
pkgtools::at_function_enter purge
${__pkg_mgr} -Qdt && pkg-notify "Purge done"
pkgtools::at_function_exit
return 0
}
function autoremove ()
{
pkgtools::at_function_enter autoremove
${__pkg_mgr} -Sc && pkg-notify "Autoremove done"
pkgtools::at_function_exit
return 0
}
fi
function extract ()
{
pkgtools::at_function_enter extract
local remove_archive
local success
local file_name
local extract_dir
if [[ "$1" == "" ]]; then
echo "Usage: extract [-option] [file ...]"
echo
echo "Options:"
echo " -r, --remove : Remove archive."
echo
fi
remove_archive=1
if [[ "$1" == "-r" ]] || [[ "$1" == "--remove" ]]; then
remove_archive=0
shift
fi
while [ -n "$1" ]; do
if [[ ! -f "$1" ]]; then
pkgtools::msg_warning "'$1' is not a valid file"
shift
continue
fi
success=0
file_name="$( basename "$1" )"
extract_dir="$( echo "$file_name" | sed "s/\.${1##*.}//g" )"
case "$1" in
(*.tar.gz|*.tgz) tar xvzf "$1" ;;
(*.tar.bz2|*.tbz|*.tbz2) tar xvjf "$1" ;;
(*.tar.xz|*.txz) tar --xz --help &> /dev/null \
&& tar --xz -xvf "$1" \
|| xzcat "$1" | tar xvf - ;;
(*.tar.zma|*.tlz) tar --lzma --help &> /dev/null \
&& tar --lzma -xvf "$1" \
|| lzcat "$1" | tar xvf - ;;
(*.tar.zstd) tar -I zstd -xvf "$1";;
(*.tar) tar xvf "$1" ;;
(*.gz) gunzip "$1" ;;
(*.bz2) bunzip2 "$1" ;;
(*.xz) unxz "$1" ;;
(*.lzma) unlzma "$1" ;;
(*.Z) uncompress "$1" ;;
(*.zip) unzip "$1" -d $extract_dir ;;
(*.rar) unrar e -ad "$1" ;;
(*.7z) 7za x "$1" ;;
(*.deb)
mkdir -p "$extract_dir/control"
mkdir -p "$extract_dir/data"
cd "$extract_dir"; ar vx "../${1}" > /dev/null
cd control; tar xzvf ../control.tar.gz
cd ../data; tar xzvf ../data.tar.gz
cd ..; rm *.tar.gz debian-binary
cd ..
;;
(*)
pkgtools::msg_error "'$1' cannot be extracted" 1>&2
success=1
;;
esac
(( success = $success > 0 ? $success : $? ))
(( $success == 0 )) && (( $remove_archive == 0 )) && rm "$1"
shift
done
pkgtools::at_function_exit
return 0
}
function compress ()
{
pkgtools::at_function_enter compress
if [[ "$1" == "" ]]; then
echo "Usage: compress [-option] dir[.tar.gz]"
echo
fi
while [ -n "$1" ]; do
local base="$(basename \"$1\")"
local filename="${base%%.*}"
local file="${base%.*}"
local dir="$(dirname \"$1\")/$filename"
local ext="${base#*.}"
if [[ ! -d "$dir" || ! -f "$file" ]]; then
pkgtools::msg_warning "'$dir' is not a valid directory/file"
shift
continue
fi
success=0
if [[ -d "$dir" ]]; then
(
cd $(dirname $1)
case "$ext" in
(tar.gz|tgz) tar czf "$1" "$filename" ;;
(tar.bz2|tbz|*.tbz2) tar cjf "$1" "$filename" ;;
(tar.xz|txz) tar --xz -cvf "$1" "$filename" ;;
(tar.zma|tlz) tar --lzma -cvf "$1" "$filename" ;;
(tar) tar cvf "$1" "$filename" ;;
(zip) zip "$dir" $dir/*;;
(*)
pkgtools::msg_error "'$dir' cannot be compressed!" 1>&2
success=1
;;
esac
)
elif [[ -f "$file" ]]; then
ext="${base##*.}"
case "$ext" in
(gz) gzip "$file" ;;
(bz2) bzip2 "$file" ;;
(xz) xz "$file" ;;
(lzma) lzma "$1" ;;
(7z) 7za x "$1" ;;
(*)
pkgtools::msg_error "'$file' $ext cannot be compressed!" 1>&2
success=1
;;
esac
fi
(( success = $success > 0 ? $success : $? ))
shift
done
pkgtools::at_function_exit
return success
}
Previous method was using https://pypi.python.org/pypi/dotfiles, since there are
still some uncontrolled things (like managing ~/.config
directory), I change it
by using a classical Makefile
# function dotfiles ()
# {
# pkgtools::at_function_enter dotfiles
# cd ~/Development/github.com/xgarrido/dotfiles
# make $@
# pkgtools::at_function_exit
# return 0
# }
# # Connect completion system
# compdef _dotfiles dotfiles
# function _dotfiles ()
# {
# local -a _actions
# _actions=(
# help:'show help'
# list:'show dot files'
# deploy:'create symlink to home directory'
# update:'fetch changes'
# install:'run update and deploy command'
# clean:'remove the dot files'
# )
# _describe -t _actions 'Actions' _actions && ret=0
# }
Base function for notification
function --notify ()
{
if pkgtools::has_binary notify-send; then
case $HOSTNAME in
garrido-laptop|nb-garrido)
notify-send $@ > /dev/null 2>&1
;;
esac
fi
return 0
}
function notify_success ()
{
--notify -t 5000 -u low -i gtk-info "notice" "${PREEXEC_CMD} $@"
return 0
}
alias notify=notify_success
function notify_error ()
{
--notify -t 5000 -u critical -i gtk-stop "error" "${PREEXEC_CMD:-Shell Command} $@"
return 0
}
These two functions are only available for zsh
shell. There are run at every
shell command and trigger notification events in case of long time command or
failling ones. This is pretty useful when long command such as compilation
command are running : user can go to another desktop do whatever he wants but
get warned when the command has finished or has failed.
function precmd ()
{
# must be first
if [ $? -ne 0 ]; then
notify_error
fi
# BEGIN notify long running cmds
stop=$(date +'%s')
start=${PREEXEC_TIME:-$stop}
let elapsed=$stop-$start
max=${PREEXEC_MAX:-10}
for i in ${PREEXEC_EXCLUDE_LIST:-}; do
if [ "x$i" = "x$PREEXEC_CMD" ]; then
max=999999;
break;
fi
done
if [ $elapsed -gt $max ]; then
notify_success "finished ($elapsed secs)"
fi
# END notify long running cmds
# Update scheme color
if (( $+functions[__load_scheme] )); then
__load_scheme
fi
return 0
}
function preexec ()
{
if [[ "$TERM" == "screen" ]]; then
local CMD=${1}
echo -ne "\ek$CMD\e\\"
fi
# for notifying of long running commands
export PREEXEC_CMD=`echo $1 | awk '{ print $1; }'`
export PREEXEC_TIME=$(date +'%s')
return 0
}
This should be improved by doing something as wakeonlan did with a small machine db.
function connect ()
{
pkgtools::at_function_enter connect
local use_screen=0
local server_name=
local ssh_option=
local append_command=
if [[ "$1" == "" ]]; then
pkgtools::msg_error "Missing the name of machine to connect !"
pkgtools::at_function_exit
return 1
fi
while [ -n "$1" ]; do
if [[ "$1" == "-s" ]]; then
use_screen=1
elif [[ "$1" == "ligo" ]]; then
[email protected]
elif [[ "$1" == "livingston" ]]; then
[email protected]
elif [[ "$1" == "livingston-dev6" ]]; then
[email protected]
elif [[ "$1" == "hanford" ]]; then
[email protected]
elif [[ "$1" == "caltech" ]]; then
[email protected]
elif [[ "$1" == "caltech-dev4" ]]; then
[email protected]
elif [[ "$1" == "caltech-dev6" ]]; then
[email protected]
elif [[ "$1" == "lyon" ]]; then
server_name="[email protected]"
elif [[ "$1" == "nersc" ]]; then
server_name="[email protected]"
elif [[ "$1" == "ruche" ]]; then
server_name="[email protected]"
elif [[ "$1" == "dell-xps" ]]; then
server_name="[email protected]"
elif [[ "$1" == "rpi" ]]; then
server_name="[email protected]"
elif [[ "$1" == "lal" ]]; then
server_name="[email protected]"
elif [[ $1 == pc-mag ]]; then
server_name="[email protected]"
fi
shift 1
done
if [ ${use_screen} -eq 0 ]; then
pkgtools::msg_notice "Connecting to ${server_name}..."
ssh ${ssh_option} ${server_name} "${append_command}"
else
pkgtools::msg_notice "Connecting to ${server_name} with screen support..."
screen ssh ${ssh_option} ${server_name}
fi
pkgtools::at_function_exit
return 0
}
# Connect completion system
compdef _connect connect
function _connect ()
{
local -a _machines
_machines=(
lyon:'CC Lyon job machines'
nersc:'NERSC machines'
dell-xps:'Laptop Dell XPS'
rpi:'Ubuntu - Raspberry Pi'
lal:'lxplus machine @ LAL'
pc-mag:'Magistère machine'
ligo:'LIGO machines'
livingston:'Livingston job machines'
livingston-dev6:'Livingston dev machines'
caltech:'Caltech job machines'
caltech-dev4:'Caltech dev4 machines'
caltech-dev6:'Caltech dev6 machines'
hanford:'Hanford job machines'
ruche:'Ruche mesocentre'
)
_describe -t _machines 'SSH machines' _machines && ret=0
}
function psgrep ()
{
pkgtools::at_function_enter psgrep
if [[ ! -z $1 ]] ; then
pkgtools::msg_notice "Grepping for processes matching $1..."
ps aux | grep $1 | grep -v grep
else
pkgtools::msg_error "Need name to grep for !"
pkgtools::at_function_exit
return 1
fi
pkgtools::at_function_exit
return 0
}
function pskill ()
{
pkgtools::at_function_enter pskill
psgrep $1 | awk '{print "kill -9",$2}' | sh
pkgtools::at_function_exit
return 0
}
function hgrep ()
{
pkgtools::at_function_enter hgrep
if [[ ! -z $1 ]] ; then
pkgtools::msg_notice "Grepping for command matching $1..."
history | grep $1
else
pkgtools::msg_error "Need name to grep for !"
pkgtools::at_function_exit
return 1
fi
pkgtools::at_function_exit
return 0
}
function remove_trailing_whitespace ()
{
pkgtools::at_function_enter remove_trailing_whitespace
if [[ ! -z $1 ]] ; then
pkgtools::msg_notice "Removing trailing whitespace in file $1..."
find $1 -type f -exec sed -i 's/ *$//' '{}' ';'
else
pkgtools::msg_error "Missing filename !"
pkgtools::at_function_exit
return 1
fi
pkgtools::at_function_exit
return 0
}
function remove_duplicate_lines ()
{
pkgtools::at_function_enter remove_duplicate_lines
if [[ ! -z $1 ]] ; then
pkgtools::msg_notice "Removing duplicate lines in file $1..."
awk '!seen[$0]++' $1 > /tmp/$(basename $1).tmp
mv /tmp/$(basename $1).tmp $1
else
pkgtools::msg_error "Missing filename !"
pkgtools::at_function_exit
return 1
fi
pkgtools::at_function_exit
return 0
}
function convert_lemonde()
{
cat $1 | awk '
BEGIN{
found = 0
process = 0
}
{
if ($0 ~ /LE MONDE/) {
if (found == 2) {print "*",prev,"\n"; process=1; $0=$0"."}
else found++
}
if ($0 ~ /Abonnez vous/) process=0
if ($0 ~ /Lire aussi/) next
if (process) {
last=($0 ~ /\./)
if (last) print $0
else if ($0 != "") print "**",$0
else print $0
}
if ($0 != "") prev=$0
}
' > $1.tmp
mv $1.tmp $1
}
function eps2tikz ()
{
pkgtools::at_function_enter eps2tikz
local use_helvetica=0
local keep_xfig=0
local remove_duplicate_lines=1
local eps_file=
local parse_switch=1
if [[ "$1" == "" ]]; then
echo "Usage: eps2tikz [-option] [eps files ...]"
echo
echo "Options:"
echo " -k, --keep-xfig : Keep the intermediate xfig file."
echo
fi
while [ -n "$1" ]; do
token="$1"
if [[ "${token[1]}" = "-" ]]; then
opt=${token}
if [[ ${parse_switch} -eq 0 ]]; then
break
fi
if [ "${opt}" = "--keep-xfig" ]; then
keep_xfig=1
elif [ "${opt}" = "--do-not-remove-duplicate-lines" ]; then
remove_duplicate_lines=0
else
pkgtools::msg_warning "Ignoring option '${opt}' !"
fi
else
arg=${token}
parse_switch=0
if [ "${arg##*.}" = "eps" ]; then
eps_file="${eps_file} ${arg}"
else
pkgtools::msg_warning "'${eps_file}' is not an Encapsulated PostScript"
fi
fi
shift
done
if [[ -z "${eps_file}" ]]; then
pkgtools::msg_error "Missing EPS file !"
pkgtools::at_function_exit
return 1
fi
for i in $(echo ${eps_file}); do
if [ ! -f "${i}" ]; then
pkgtools::msg_warning "File ${i} does not exist! Skip it"
continue
fi
local fig_file=${i/.eps/.fig}
local tikz_file=${i/.eps/.tikz}
pkgtools::msg_notice "Converting ${i} file to ${tikz_file}..."
if [[ ! -x $(which pstoedit) ]]; then
pkgtools::msg_error "Missing 'pstoedit' binary !"
pkgtools::at_function_exit
return 1
fi
pstoedit -f xfig "${i}" > ${fig_file} 2> /dev/null
if [[ ! -x $(which fig2tikz) ]]; then
pkgtools::msg_error "Missing fig2tikz' binary !"
pkgtools::at_function_exit
return 1
fi
fig2tikz ${fig_file} > ${tikz_file}.tmp
if [[ ${remove_duplicate_lines} -eq 1 ]]; then
pkgtools::msg_notice "Remove duplicate lines..."
awk '{if (match($0,"definecolor") || !seen[$0]++) {print $0}}' ${tikz_file}.tmp > ${tikz_file}
else
cp ${tikz_file}.tmp ${tikz_file}
fi
rm -f ${tikz_file}.tmp
if [[ ${keep_xfig} -eq 0 ]]; then
rm -f ${fig_file}
fi
done
pkgtools::at_function_exit
return 0
}
# completion system
compdef _eps2tikz eps2tikz
function _eps2tikz ()
{
_arguments -C \
'(-v --verbose)'{-v,--verbose}'[verbose output]' \
'(-h --help)'{-h,--help}'[print help message]' \
--keep-xfig'[Keep Xfig files]' \
--do-not-remove-duplicate-lines'[do not edit tikz file by removing duplicated lines]' \
"*:filename: _alternative 'files:file:_files -g \"*.eps\"'" && ret=0
}
Dexter is a little java program to interactively or semi-automatically extract data from scanned graphs. In its applet incarnation it is used by the Astrophysics Data System.
function dexter ()
{
pkgtools::at_function_enter dexter
if [[ "$1" == "" ]]; then
echo "Usage: dexter [image files ...]"
echo
pkgtools::at_function_exit
return 1
else
java -jar /home/garrido/Workdir/Development/java/dexter/Debuxter.jar $1
fi
pkgtools::at_function_exit
return 0
}
function plot2pdf()
{
local dirs
local files
local options
for i in $@
do
if [ -f $i ]; then
files+="$i "
elif [ -d $i ]; then
dirs+="$i "
else
options+="$i "
fi
done
if [[ -z ${dirs} && -z ${files} ]]; then
pkgtools::msg_notice "Adding current directory"
dirs="."
fi
for d in ${=dirs}
do
for f in $(find $d -name "*.pgf" -o -name "*.tikz")
do
files+="$f "
done
done
for f in ${=files}
do
file=$(echo $f)
base=${f%.*}
pdf=$base.pdf
if [[ ! -a $pdf || $file -nt $pdf ]]; then
# Remove 'Dimension too large'
sed -i -e 's/\(.*pgfqpoint{.*}{\)\(-[2-9][0-9][0-9]\)\(.*in}.*\)/\1-200\3/g' $file
eval $(echo tikz2pdf ${options} ${file})
else
pkgtools::msg_notice "File '$file' already processed"
fi
done
}
compdef _tikz2pdf plot2pdf
function flac2mp3() {
if [[ "$1" == "" ]]; then
echo "Usage: flac2mp3 [flac files ...]"
echo
return 1
fi
if (( $+commands[parallel] )); then
parallel ffmpeg -i {} -qscale:a 0 {.}.mp3 ::: $1/**/*.flac
else
pkgtools::msg_error "Missing parallel package!"
return 1
fi
return 0
}
function google-music-uploader()
{
if [ ! -d /tmp/gmusic ]; then
pkgtools::msg_notice "Creating virtual env for gmusicapi"
python3 -m venv /tmp/gmusic
fi
source /tmp/gmusic/bin/activate
pip install google-music-manager-uploader
if [ ! -f ~/.auth.key ]; then
google-music-auth ~/.auth.key
fi
sed -i -e 's/eth0/wlp2s0/' /tmp/gmusic/lib/python3.8/site-packages/google_music_manager_uploader/uploader_daemon.py
google-music-upload -d /home/garrido/Musique -a ~/.auth.key -r
}
function usb_umount()
{
for d in /run/media/*; do
sudo umount $d
done
sudo modprobe usb_storage
}
function svnstatus ()
{
pkgtools::at_function_enter svnstatus
templist=$(svn status $*)
echo "$(echo $templist | grep '^?' | wc -l) unversioned files/directories"
echo $templist | grep -v '^?'
pkgtools::at_function_exit
return 0
}
function svndiff ()
{
pkgtools::at_function_enter svndiff
svn diff $* | code2color -l patch -
pkgtools::at_function_exit
return 0
}
Original work done by supercrabtree
zmodload zsh/datetime
zmodload -F zsh/stat b:zstat
k () {
# ----------------------------------------------------------------------------
# Setup
# ----------------------------------------------------------------------------
# Stop stat failing when a directory contains either no files or no hidden files
# Track if we _accidentally_ create a new global variable
setopt local_options null_glob warn_create_global
# Turn on 256 colour terminal, not sure this works at all.
typeset OLD_TERM="$TERM"
TERM='xterm-256color'
# ----------------------------------------------------------------------------
# Vars
# ----------------------------------------------------------------------------
typeset -a MAX_LEN A RESULTS STAT_RESULTS
typeset TOTAL_BLOCKS
# Get now
typeset K_EPOCH="${EPOCHSECONDS:?}"
typeset -i TOTAL_BLOCKS=0
MAX_LEN=(0 0 0 0 0 0)
# Array to hold results from `stat` call
RESULTS=()
# only set once so must be out of the main loop
typeset -i IS_GIT_REPO=0
typeset -i LARGE_FILE_COLOR=196
typeset -a SIZELIMITS_TO_COLOR
# SIZELIMITS_TO_COLOR=(
# 1024 46 # <= 1kb
# 2048 82 # <= 2kb
# 3072 118 # <= 3kb
# 5120 154 # <= 5kb
# 10240 190 # <= 10kb
# 20480 226 # <= 20kb
# 40960 220 # <= 40kb
# 102400 214 # <= 100kb
# 262144 208 # <= 0.25mb || 256kb
# 524288 202 # <= 0.5mb || 512kb
# )
SIZELIMITS_TO_COLOR=(
1024 226 # <= 1kb
2048 220 # <= 2kb
5120 214 # <= 5kb
524288 208 # <= 512kb
1024000 202 # <= 1Mb
)
typeset -i ANCIENT_TIME_COLOR=252 # > more than 2 years old
typeset -a FILEAGES_TO_COLOR
FILEAGES_TO_COLOR=(
0 196 # < in the future, #spooky
60 236 # < less than a min old
3600 238 # < less than an hour old
86400 240 # < less than 1 day old
604800 242 # < less than 1 week old
2419200 244 # < less than 28 days (4 weeks) old
15724800 244 # < less than 26 weeks (6 months) old
31449600 250 # < less than 1 year old
62899200 252 # < less than 2 years old
)
# ----------------------------------------------------------------------------
# Stat call to get directory listing
# ----------------------------------------------------------------------------
# Break total blocks of the front of the stat call, then push the rest to results
typeset -i i=1 j=1 k=1
typeset -a STATS_PARAMS_LIST
typeset fn statvar
typeset -A sv
# for fn in . .. *(D)
for fn in $(command \ls -rt $@)
do
if [[ $fn == "." || $fn == ".." ]]; then continue; fi
statvar="stats_$i"
typeset -A $statvar
zstat -H $statvar -Lsn -F "%s^%d^%b^%H:%M^%Y" -- "$fn" # use lstat, render mode/uid/gid to strings
STATS_PARAMS_LIST+=($statvar)
i+=1
done
# On each result calculate padding by getting max length on each array member
for statvar in "${STATS_PARAMS_LIST[@]}"
do
sv=("${(@Pkv)statvar}")
if [[ ${#sv[mode]} -gt $MAX_LEN[1] ]]; then MAX_LEN[1]=${#sv[mode]} ; fi
if [[ ${#sv[nlink]} -gt $MAX_LEN[2] ]]; then MAX_LEN[2]=${#sv[nlink]} ; fi
if [[ ${#sv[uid]} -gt $MAX_LEN[3] ]]; then MAX_LEN[3]=${#sv[uid]} ; fi
if [[ ${#sv[gid]} -gt $MAX_LEN[4] ]]; then MAX_LEN[4]=${#sv[gid]} ; fi
if [[ ${#sv[size]} -gt $MAX_LEN[5] ]]; then MAX_LEN[5]=${#sv[size]} ; fi
TOTAL_BLOCKS+=$sv[blocks]
done
# Print total block before listing
echo "total $TOTAL_BLOCKS"
# ----------------------------------------------------------------------------
# Loop through each line of stat, pad where appropriate and do git dirty checking
# ----------------------------------------------------------------------------
typeset REPOMARKER
typeset PERMISSIONS HARDLINKCOUNT OWNER GROUP FILESIZE DATE NAME SYMLINK_TARGET
typeset FILETYPE PER1 PER2 PER3 PERMISSIONS_OUTPUT STATUS
typeset TIME_DIFF TIME_COLOR DATE_OUTPUT
typeset -i IS_DIRECTORY IS_SYMLINK IS_EXECUTABLE
typeset -i COLOR
k=1
for statvar in "${STATS_PARAMS_LIST[@]}"
do
sv=("${(@Pkv)statvar}")
# We check if the result is a git repo later, so set a blank marker indication the result is not a git repo
REPOMARKER=""
IS_DIRECTORY=0
IS_SYMLINK=0
IS_EXECUTABLE=0
PERMISSIONS="${sv[mode]}"
HARDLINKCOUNT="${sv[nlink]}"
OWNER="${sv[uid]}"
GROUP="${sv[gid]}"
FILESIZE="${sv[size]}"
DATE=(${(s:^:)sv[mtime]}) # Split date on ^
NAME="${sv[name]}"
SYMLINK_TARGET="${sv[link]}"
# Check for file types
if [[ -d "$NAME" ]]; then IS_DIRECTORY=1; fi
if [[ -L "$NAME" ]]; then IS_SYMLINK=1; fi
# is this a git repo
if [[ $k == 1 && $(command git rev-parse --is-inside-work-tree 2>/dev/null) == true ]]
then
IS_GIT_REPO=1
fi;
# Pad so all the lines align - firstline gets padded the other way
PERMISSIONS="${(r:MAX_LEN[1]:)PERMISSIONS}"
HARDLINKCOUNT="${(l:MAX_LEN[2]:)HARDLINKCOUNT}"
OWNER="${(l:MAX_LEN[3]:)OWNER}"
GROUP="${(l:MAX_LEN[4]:)GROUP}"
FILESIZE="${(l:MAX_LEN[5]:)FILESIZE}"
# --------------------------------------------------------------------------
# Colour the permissions - TODO
# --------------------------------------------------------------------------
# Colour the first character based on filetype
FILETYPE="${PERMISSIONS[1]}"
# if (( IS_DIRECTORY ))
# then
# FILETYPE=${FILETYPE//d/$'\e[01;38;5;004m'd$'\e[0m'};
# elif (( IS_SYMLINK ))
# then
# FILETYPE=${FILETYPE//l/$'\e[0;35m'l$'\e[0m'};
# elif [[ $FILETYPE == "-" ]];
# then
# FILETYPE=${FILETYPE//-/$'\e[0;37m'-$'\e[0m'};
# fi
# Permissions Owner
PER1="${PERMISSIONS[2,4]}"
# Permissions Group
PER2="${PERMISSIONS[5,7]}"
# Permissions User
PER3="${PERMISSIONS[8,10]}"
PERMISSIONS_OUTPUT="$FILETYPE$PER1$PER2$PER3"
# --x --x --x warning
if [[ $PER1[3] == "x" || $PER2[3] == "x" || $PER3[3] == "x" ]]; then IS_EXECUTABLE=1; fi
# --- --- rwx warning
if [[ $PER3 == "rwx" && IS_SYMLINK == 0 ]]; then PERMISSIONS_OUTPUT=$'\e[30;41m'"$PERMISSIONS"$'\e[0m'; fi
# --------------------------------------------------------------------------
# Colour the symlinks - TODO
# --------------------------------------------------------------------------
# --------------------------------------------------------------------------
# Colour Owner and Group
# --------------------------------------------------------------------------
# OWNER=$'\e[38;5;011m'"$OWNER"$'\e[0m'
# GROUP=$'\e[38;5;009m'"$GROUP"$'\e[0m'
# --------------------------------------------------------------------------
# Colour file weights
# --------------------------------------------------------------------------
COLOR=LARGE_FILE_COLOR
for i j in ${SIZELIMITS_TO_COLOR[@]}
do
(( FILESIZE <= i )) || continue
COLOR=$j
break
done
FILESIZE="$(command numfmt --to=si --format="%4f" $FILESIZE)"
FILESIZE=$'\e[38;5;'"${COLOR}m$FILESIZE"$'\e[0m'
# --------------------------------------------------------------------------
# Colour the date and time based on age, then format for output
# --------------------------------------------------------------------------
# Setup colours based on time difference
TIME_DIFF=$(( K_EPOCH - DATE[1] ))
TIME_COLOR=$ANCIENT_TIME_COLOR
for i j in ${FILEAGES_TO_COLOR[@]}
do
(( TIME_DIFF < i )) || continue
TIME_COLOR=$j
break
done
# Format date to show year if more than 6 months since last modified
if (( TIME_DIFF < 15724800 )); then
DATE_OUTPUT="${DATE[2]} ${(r:5:: :)${DATE[3][0,5]}} ${DATE[4]}"
else
DATE_OUTPUT="${DATE[2]} ${(r:6:: :)${DATE[3][0,5]}} ${DATE[5]}" # extra space; 4 digit year instead of 5 digit HH:MM
fi;
DATE_OUTPUT[1]="${DATE_OUTPUT[1]//0/ }" # If day of month begins with zero, replace zero with space
# # Apply colour to formated date
# DATE_OUTPUT=$'\e[38;5;'"${TIME_COLOR}m${DATE_OUTPUT}"$'\e[0m'
# --------------------------------------------------------------------------
# Colour the repomarker
# --------------------------------------------------------------------------
# # Check for git repo, first checking if the result is a directory
# if (( IS_GIT_REPO == 0)) || (( k <= 2 ))
# then
# if (( IS_DIRECTORY )) && [[ -d "$NAME/.git" ]]
# then
# if command git --git-dir="$PWD/$NAME/.git" --work-tree="$PWD/$NAME" diff --quiet --ignore-submodules HEAD &>/dev/null # if dirty
# then REPOMARKER=$'\e[38;5;46m|\e[0m' # Show a green vertical bar for dirty
# else REPOMARKER=$'\e[0;31m|\e[0m' # Show a red vertical bar if clean
# fi
# fi
# fi
if (( IS_GIT_REPO )) && (( k > 0 )) && [[ "$NAME" != '.git' ]]
then
STATUS="$(command git status --porcelain --ignored --untracked-files=normal "$NAME")"
STATUS="${STATUS[1,2]}"
if [[ $STATUS == ' M' ]]; then REPOMARKER=$'\e[01;38;5;001m✘\e[0m'; # Modified
elif [[ $STATUS == '??' ]]; then REPOMARKER=$'\e[01;38;5;009m⚑\e[0m'; # Untracked
elif [[ $STATUS == '!!' ]]; then REPOMARKER=$'\e[01;38;5;004m⚐\e[0m'; # Ignored
elif [[ $STATUS == 'A ' ]]; then REPOMARKER=$'\e[01;38;5;093m|\e[0m'; # Added
else REPOMARKER=$'\e[01;38;5;002m✔\e[0m'; # Good
fi
fi
# --------------------------------------------------------------------------
# Colour the filename
# --------------------------------------------------------------------------
# Unfortunately, the choices for quoting which escape ANSI color sequences are q & qqqq; none of q- qq qqq work.
# But we don't want to quote '.'; so instead we escape the escape manually and use q-
NAME="${(q-)NAME//$'\e'/\\e}" # also propagate changes to SYMLINK_TARGET below
if (( IS_SYMLINK ))
then
NAME=$'\e[07;38;5;4m'"$NAME"$'\e[0m'
elif (( IS_DIRECTORY ))
then
NAME=$'\e[01;38;5;4m'"$NAME"$'\e[0m'
fi
# --------------------------------------------------------------------------
# Format symlink target
# --------------------------------------------------------------------------
if [[ $SYMLINK_TARGET != "" ]]; then SYMLINK_TARGET="-> ${(q-)SYMLINK_TARGET//$'\e'/\\e}"; fi
#SYMLINK_TARGET=$'\e[38;5;27m'"$SYMLINK_TARGET"$'\e[0m'
# --------------------------------------------------------------------------
# Display final result
# --------------------------------------------------------------------------
print -r -- "$PERMISSIONS_OUTPUT $HARDLINKCOUNT $OWNER $GROUP $FILESIZE $DATE_OUTPUT $REPOMARKER $NAME $SYMLINK_TARGET"
# print -r -- "$FILESIZE $DATE_OUTPUT $REPOMARKER $NAME $SYMLINK_TARGET"
k=$((k+1)) # Bump loop index
done
# cleanup / recovery
TERM="$OLD_TERM"
}
# http://upload.wikimedia.org/wikipedia/en/1/15/Xterm_256color_chart.svg
function t()
{
arguments="$@"
skip_ignore_files=0
if [[ $arguments == *--skip-ignore-files* ]]; then
skip_ignore_files=1
arguments=${@/--skip-ignore-files/}
fi
tree -ft $(echo $arguments) | awk -v skip_ignore_files=$skip_ignore_files '{
status=""
marker=" "
color="\033[0m"
# if (system("test -f " $NF) == 0) print "file="$NF
if (system("test -d " $NF) == 0) {
is_git_repo=system("git rev-parse --is-inside-work-tree > /dev/null 2>&1")
color="\033[01;38;5;004m"
marker=""
}
if (is_git_repo == 0) {
cmd = "git status --porcelain --ignored --untracked-files=normal \"" $NF "\""
cmd | getline status
status=substr(status,1,2)
if (status == " M") {
color="\033[38;5;001m"
marker="✘ "
} else if (status == "??") {
color="\033[38;5;009m"
marker="⚑ "
} else if (status == "!!") {
color="\033[38;5;004m"
marker=color "⚐ "
if (skip_ignore_files) next
} else if (status == "A ") {
color="\033[38;5;093m"
marker="| "
} else {
color="\033[38;5;002m"
marker="✔ "
}
}
basefile=$NF
sub(".*/",color marker,basefile)
sub($NF,basefile,$0)
print $0 "\033[0m"
}'
}
alias tt='t -L 1'
alias ta='t -a -L 1'
alias ti='t --skip-ignore-files'
function countdown()
{
date1=$((`date +%s` + $1));
while [ "$date1" -ne `date +%s` ]; do
echo -ne "$(date -u --date @$(($date1 - `date +%s`)) +%H:%M:%S)\r";
sleep 0.1
done
}
function stopwatch()
{
date1=`date +%s`;
while true; do
echo -ne "$(date -u --date @$((`date +%s` - $date1)) +%H:%M:%S)\r";
sleep 0.1
done
}
# termcap
# ks make the keypad send commands
# ke make the keypad send digits
# vb emit visual bell
# mb start blink
# md start bold
# me turn off bold, blink and underline
# so start standout (reverse video)
# se stop standout
# us start underline
# ue stop underline
function man()
{
env \
LESS_TERMCAP_mb=$(printf "\e[1;34m") \
LESS_TERMCAP_md=$(printf "\e[1;34m") \
LESS_TERMCAP_me=$(printf "\e[0m") \
LESS_TERMCAP_so=$(printf "\e[1;47;33m") \
LESS_TERMCAP_se=$(printf "\e[0m") \
LESS_TERMCAP_us=$(printf "\e[1;32m") \
LESS_TERMCAP_ue=$(printf "\e[0m") \
PAGER="${commands[less]:-$PAGER}" \
man "$@"
}
function youtube-dl()
{
if [ ! -d /tmp/youtube-dl ]; then
pkgtools::msg_notice "Creating virtual env for youtube-dl"
python3 -m venv /tmp/youtube-dl
source /tmp/youtube-dl/bin/activate
# pip install --upgrade --force-reinstall "git+https://github.com/ytdl-org/youtube-dl.git"
pip install --upgrade --force-reinstall "git+https://github.com/yt-dlp/yt-dlp.git"
fi
#pip install youtube-dl
/tmp/youtube-dl/bin/yt-dlp $@
}
function webm2mp3()
{
for f in *.webm; do
if [ ! -f ${f/webm/mp3} ]; then
pkgtools::msg_notice "Converting $f..."
ffmpeg -i "$f" -ab 160k -ar 44100 "${f/webm/mp3}"
new_name=$(echo $f | sed 's/\(.*\)\( \[.*\)/\1.mp3/')
mv "${f/webm/mp3}" "${new_name}"
fi
done
}
function grab_video ()
{
pkgtools::at_function_enter grab_video
if [[ ! -z $1 ]] ; then
pkgtools::msg_notice "Grabing video from $1 link and saving it to /tmp/dump_video.avi..."
mplayer -dumpstream "$1" -dumpfile /tmp/dump_video.avi
else
pkgtools::msg_error "Missing mms link !"
pkgtools::at_function_exit
return 1
fi
pkgtools::at_function_exit
return 0
}
function bak ()
{
pkgtools::at_function_enter bak
if [ -z $1 ]; then
pkgtools::msg_error "Missing file or directory name !"
pkgtools::at_function_exit
return 1
fi
[ -f $1 ] && cp $1 $1.bak
[ -d $1 ] && cp -r $1 $1.bak
pkgtools::at_function_exit
return 0
}
function unbak ()
{
pkgtools::at_function_enter unbak
if [ -z $1 ]; then
pkgtools::msg_error "Missing file or directory name !"
pkgtools::at_function_exit
return 1
fi
if [[ ${1##*.} != "bak" ]]; then
pkgtools::msg_error "$1 is not a backup copy !"
pkgtools::at_function_exit
return 1
fi
unbak_name=${1/.bak/}
if [[ -f ${unbak_name} || -d ${unbak_name} ]]; then
pkgtools::msg_warning "File or directory ${unbak_name} already exists !"
return 1
fi
[ -f $1 ] && mv $1 ${1/.bak/}
[ -d $1 ] && mv $1 ${1/.bak/}
pkgtools::at_function_exit
return 0
}
function search_student ()
{
pkgtools::at_function_enter search_student
if [ -z $1 ]; then
pkgtools::msg_error "Missing student name !"
pkgtools::at_function_exit
return 1
elif [[ $1 == "--help" || $1 == "-h" ]]; then
pkgtools::msg_notice "Usage : search_student \"firstname lastname\""
pkgtools::at_function_exit
return 0
fi
adonis_http="http://adonis.u-psud.fr/users"
adonis_pics_path="/tmp/adonis_pics"
mkdir -p ${adonis_pics_path}
names=$(echo $1 | sed 's/ /./g')
for name in ${names}
do
nname=$(echo $name | iconv -f utf8 -t ascii//TRANSLIT)
prefix="Getting picture for $nname"
if [ -f ${adonis_pics_path}/${nname}.jpg ]; then
pkgtools::msg_notice "${prefix} -> already downloaded"
xdg-open ${adonis_pics_path}/${nname}.jpg &
continue
fi
for i in 0 1 2 3
do
http_path=${adonis_http}/sl$i/${nname:0:1}/${nname}/
wget -r --no-parent -A "*.jpg" ${http_path} -P /tmp > /dev/null 2>&1
if [ $? -eq 0 ]; then
pkgtools::msg_notice "${prefix} -> picture found"
ls -1 /tmp/${http_path/http:\/\//}/*.jpg | tail -n1 | xargs -i cp {} ${adonis_pics_path}/${nname}.jpg
xdg-open ${adonis_pics_path}/${nname}.jpg &
break
elif [ $i -eq 3 ]; then
pkgtools::msg_error "${prefix} -> picture not found"
pkgtools::at_function_exit
return 1
fi
done
done
pkgtools::at_function_exit
return 0
}
function kill_offlineimap()
{
pids=$(psgrep offlineimap | awk '{print $2}')
for pid in ${=pids}; do
kill -9 $pid
done
}
function get_ip()
{
dig +short myip.opendns.com @resolver1.opendns.com
}
function activate-venv()
{
dir=pyenv
while [ -n "$1" ]; do
token="$1"
if [[ "${token[1]}" = "-" ]]; then
opt=${token}
if [ "${opt}" = "--dir" ]; then
shift 1
dir="$1"
else
pkgtools::msg_warning "Ignoring option '${opt}' !"
fi
else
arg=${token}
fi
shift
done
source ${dir}/bin/activate
}
function create-venv()
{
dir=pyenv
install_scientific=false
while [ -n "$1" ]; do
token="$1"
if [[ "${token[1]}" = "-" ]]; then
opt=${token}
if [ "${opt}" = "--dir" ]; then
shift 1
dir="$1"
elif [ "${opt}" = "--install-scientific" ]; then
install_scientific=true
else
pkgtools::msg_warning "Ignoring option '${opt}' !"
fi
else
arg=${token}
fi
shift 1
done
if [ -d ${dir} ]; then
pkgtools::msg_error "Directory '${dir}' already exists"
return 1
fi
python -m venv ${dir}
source ${dir}/bin/activate
python -m pip install -U pip wheel
pkgtools::msg_info "Virtual env. created and sourced!"
}
function upgrade-venv()
{
pkgtools::msg_info "Upgrading pip first"
python -m pip install --upgrade pip
while read -r line; do
if [[ $line == *"@"* ]]; then
continue
fi
name=$(echo $line | cut -d= -f1)
pkgtools::msg_info "Upgrading ${name}..."
python -m pip install --upgrade ${name} | grep --color=never --line-buffered -E -v "Requirement already satisfied:|Defaulting to user"
done <<< $(pip freeze | grep -E -v "#|^-e")
pkgtools::msg_info "Upgrade python env done"
}
function upgrade-science()
{
python -m pip install --upgrade numpy pandas scipy matplotlib seaborn $@
pkgtools::msg_info "Upgrade python env done"
}
function fix_zsh_history()
{
pkgtools::msg_info "Fix zsh corrupt file..."
mv ~/.zsh_history ~/.zsh_history.bad
strings ~/.zsh_history.bad > ~/.zsh_history
fc -R ~/.zsh_history
rm ~/.zsh_history.bad
}