## -*- mode:sh -*- # ################################################################################ ## Shell -- Functions. ## Date 2012-08-11 ################################################################################ ## Colored man pager. man() { env \ LESS_TERMCAP_mb=$(printf "\e[1;31m") \ LESS_TERMCAP_md=$(printf "\e[1;31m") \ LESS_TERMCAP_me=$(printf "\e[0m") \ LESS_TERMCAP_se=$(printf "\e[0m") \ LESS_TERMCAP_so=$(printf "\e[1;44;33m") \ LESS_TERMCAP_ue=$(printf "\e[0m") \ LESS_TERMCAP_us=$(printf "\e[1;32m") \ man "$@" } ## Make directories and change into the first one. mkcd () { mkdir -p "$@" cd "$1" } ## Quick search. search() { find . -iname "*$1*" } ## Cut last n lines in file, 10 by default. cuttail() { local nlines=${2:-10} sed -n -e ":begin ; 1,${nlines}!{P;N;D} ; N ; b begin" $1 } ## Cut first n lines in file, 10 by default. cuthead() { local nlines=${2:-10} sed -n -e "1,${nlines}!p" $1 } ## Move filenames to lowercase. ## Use ranger + bulkrename + vim/emacs (+ TwindleCase) for more flexibility. renamelower() { local file local filename local dirname for file ; do filename=${file##*/} case "$filename" in */*) dirname="${file%/*}" ;; *) dirname="." ;; esac local nf=$(echo $filename | tr A-Z a-z) local newname="${dirname}/${nf}" if [ "$nf" != "$filename" ]; then mv "$file" "$newname" echo "lowercase: $file --> $newname" else echo "lowercase: $file not changed." fi done } ## Swap 2 filenames around. renameswap() { local TEMPFILE="$(mktemp)" mv "$1" "$TEMPFILE" mv "$2" "$1" mv "$TEMPFILE" "$2" } ## Finds directory sizes and lists them for the current directory. dirsize () { local TEMPFILE="$(mktemp)" # du -shx * 2> /dev/null | \ du -shx * .[a-zA-Z0-9_]* 2> /dev/null | \ egrep '^ *[0-9.]*[MG]' | sort -n > "${TEMPFILE}" egrep '^ *[0-9.]*M' "${TEMPFILE}" egrep '^ *[0-9.]*G' "${TEMPFILE}" rm -rf "${TEMPFILE}" } ## Network operations if [ -e "/usr/bin/nmap" ]; then network-map() { echo "$1" for SCANIP in $( nmap -sL "$1" | grep -i "\([[:digit:]]\+\.\)\{3,\}[[:digit:]]\+" | awk '{print $5}' ); do sudo nmap -oX - -n -sT -T Normal -O -sR -I -F -P0 "$SCANIP" echo done } fi netspeed () { local INTERFACE="eth0" if [ -n "$1" ]; then INTERFACE="$1" fi if [ ! -d "/sys/class/net/${INTERFACE}" ]; then echo "Error: no such interface (${INTERFACE})" return fi local RX_BEFORE=$(cat /sys/class/net/${INTERFACE}/statistics/rx_bytes) local TX_BEFORE=$(cat /sys/class/net/${INTERFACE}/statistics/tx_bytes) sleep 1 local RX_AFTER=$(cat /sys/class/net/${INTERFACE}/statistics/rx_bytes) local TX_AFTER=$(cat /sys/class/net/${INTERFACE}/statistics/tx_bytes) local RX_RESULT=$(((${RX_AFTER:-0}-${RX_BEFORE:-0})/1024)) local TX_RESULT=$(((${TX_AFTER:-0}-${TX_BEFORE:-0})/1024)) echo "RX $RX_RESULT KiB/s" echo "TX $TX_RESULT KiB/s" } ## CPU usage ## ## A typical CPU array is (on Linux Kernel 3.0) ## cpu 158150 0 52354 18562746 1472 0 10198 0 0 0 ## ## The meanings of the columns are as follows, from left to right: ## ## user: normal processes executing in user mode ## nice: niced processes executing in user mode ## system: processes executing in kernel mode ## idle: twiddling thumbs ## iowait: waiting for I/O to complete ## irq: servicing interrupts ## softirq: servicing softirqs ## ... (see 'man 5 proc' for further details) ## ## Only the first 4 values are interesting here. cpuusage() { local cpuarray local f1 local f2 local f3 local f4 cpuarray="$(grep 'cpu ' /proc/stat)" f1=$(echo $cpuarray | cut -f3 -d' ') f2=$(echo $cpuarray | cut -f4 -d' ') f3=$(echo $cpuarray | cut -f5 -d' ') f4=$(echo $cpuarray | cut -f6 -d' ') local totalA=$(($f1+$f2+$f3+$f4)) local idleA=$f4 sleep 0.4 cpuarray="$(grep 'cpu ' /proc/stat)" f1=$(echo $cpuarray | cut -f3 -d' ') f2=$(echo $cpuarray | cut -f4 -d' ') f3=$(echo $cpuarray | cut -f5 -d' ') f4=$(echo $cpuarray | cut -f6 -d' ') local totalB=$(($f1+$f2+$f3+$f4)) local idleB=$f4 local totaldiff=$((${totalB:-0}-${totalA:-0})) if [ $totaldiff -eq 0 ]; then echo 0 else echo "$((100 - 100 * ($idleB-$idleA) / $totaldiff ))" fi } codescan () { IFS=" " for i in $(find . -type f -size -50M -print); do echo -n "# " file "$i" grep -m1 "\`" "$i" grep -m1 "oe" "$i" done } ## Confert all 'bad' encoding to UTF-8/LF. # ## It will fail for encoding other than ISO-8859-1 and cp1252. utf8conv () { local CODING IFS=" " for i in $(find . -type f -size -50M -print); do CODING=$(file "$i") if [ -n "$(echo $CODING | grep 'ISO-8859')" ]; then echo "ISO-8859: [$i]" recode latin1..utf-8 "$i" elif [ -n "$(echo $CODING | grep 'Non-ISO extended-ASCII')" ]; then echo "cp1252: [$i]" recode cp1252..utf-8 "$i" elif [ -n "$(echo $CODING | grep 'UTF-16 Unicode text')" ]; then echo "UTF-16: [$i]" recode utf-16..utf-8 "$i" elif [ -n "$(echo $CODING | grep 'UTF-8 Unicode (with BOM)')" ]; then echo "UTF-8 BOM: [$i]" sed -i '1s/^.//' "$i" ## The following commands work, but may be overkill. # dd iflag=skip_bytes skip=3 if=file.srt of=temp.srt # dd bs=1 skip=3 if=file.srt of=temp.srt # tail -c +32 file.srt > temp.srt fi if [ -n "$(echo $CODING | grep 'CRLF')" ]; then echo "CRLF: [$i]" sed -i 's/\r//g' "$i" fi done } ## Webcam webcam () { ## With mplayer. mplayer -fps 30 -tv driver=v4l2:width=640:height=480:device=/dev/video0 tv:// -flip } ## Vim-only: search the vim reference manual for a keyword. ## Usage: :h if [ -e "/usr/bin/vim" ]; then :h() { vim --cmd ":silent help $@" --cmd "only"; } fi ## Set file/directory owner and permissions. ## Usage: sanitize [FOLDER] sanitize() { local WORKDIR="$PWD" if [ $# -eq 1 ]; then WORKDIR="$1" fi local FMASK=$(umask -S | sed 's/x//g') local DMASK=$(umask -S) find "$WORKDIR" -exec chown -R ${UID}:${GID} {} \; find "$WORKDIR" -type d -exec chmod ${DMASK} {} \; find "$WORKDIR" -type f -exec chmod ${FMASK} {} \; } asciify() { asciify_help() { echo echo "Usage:" echo -e "\t$1 FILES" echo echo "Synopsis:" echo -e "\tConvert non-ASCII characters to their ASCII equivalent." echo } if [ $# -eq 0 ]; then echo "Missing arguments." asciify_help $0 return fi for i; do sed -i \ -e 's/[áàâä]/a/g' \ -e 's/[éèêë]/e/g' \ -e 's/[íìîï]/i/g' \ -e 's/[óòôö]/o/g' \ -e 's/[úùûü]/u/g' \ -e 's/[ýỳŷÿ]/y/g' \ -e 's/[ÁÀÂÄ]/A/g' \ -e 's/[ÉÈÊË]/E/g' \ -e 's/[ÍÌÎÏ]/I/g' \ -e 's/[ÓÒÔÖ]/O/g' \ -e 's/[ÚÙÛÜ]/U/g' \ -e 's/[ÝỲŶŸ]/Y/g' \ -e 's/[ñ]/n/g' \ -e 's/[œ]/oe/g' \ -e 's/[Œ]/Oe/g' \ -e 's/[æ]/ae/g' \ -e 's/[Æ]/Ae/g' \ -e 's/[ç]/c/g' \ -e 's/[Ç]/C/g' \ -e 's/[ß]/ss/g' \ -e 's/[«»„“”‚‘’]/"/g' \ -e 's/[©]/(C)/g' \ -e 's/[®]/(R)/g' \ -e 's/[™]/(TM)/g' \ -e 's/[¥]/Y/g' \ -e 's/[Ð]/D/g' \ -e 's/[ŀ]/l/g' \ -e 's/[Ŀ]/L/g' \ -e 's/[€]/euro/g' \ -e 's/[¢]/cent/g' \ -e 's/[£]/pound/g' \ -e 's/[µ]/mu/g' \ -e 's/[²]/^2/g' \ -e 's/[³]/^3/g' \ -e 's/[¡]/!/g' \ -e 's/[¿]/?/g' \ -e 's/[–‑]/-/g' \ -e 's/[…]/.../g' \ -e 's/[≤]/<=/g' \ -e 's/[≥]/>=/g' \ -e 's/[±]/+\/-/g' \ -e 's/[≠]/!=/g' \ -e 's/[⋅]/./g' \ -e 's/[×]/x/g' \ -e 's/[÷]/\//g' \ -e 's/[↓]/|/g' \ -e 's/[↑]/^/g' \ -e 's/[←]/<=/g' \ -e 's/[→]/=>/g' \ "$i" done; } blind-append() { blind_help() { echo echo "Usage:" echo -e "\t$1 FILE [STRING]" echo echo "Synopsis:" echo -e "\tAppend to all STRING found in FILE a secret phrase being prompted." echo -e "\tIf STRING is omitted, secret phrase will be appended to the end of the file." echo -e "\tIf FILE does not exist, it will be created and secret phrase will be inserted. STRING will be ignored." echo } if [ $# -gt 2 ] || [ $# -lt 1 ]; then echo "Wrong number of arguments." blind_help $0 return fi local FILE="$1" local STRING="" local DUMMY if [ $# -eq 2 ]; then STRING="$2" fi echo -n "Secret: " read -s DUMMY echo "" if [ ! -e "$FILE" ] || [ -z "$STRING" ]; then echo "$DUMMY" >> "$FILE" echo "Secret appended to ${FILE} at the end." return fi if [ $# -eq 1 ]; then echo "$DUMMY" >> "$FILE" else sed -i "s/${STRING}/${STRING}${DUMMY}/g" "${FILE}" fi echo "Secret appended to ${FILE}." return } ## Term properties termcolors256() { x=$(tput op) y=$(printf %76s) for i in {0..256}; do o=00$i echo -e "${o:${#o}-3:3} $(tput setaf $i;tput setab $i)${y// /=}$x" done } termcolors() { # The test text. Must be 3 letters. T='Doh' echo -e "\n 40m 41m 42m 43m\ 44m 45m 46m 47m"; for FGs in ' m' ' 1m' ' 30m' '1;30m' ' 31m' '1;31m' ' 32m' \ '1;32m' ' 33m' '1;33m' ' 34m' '1;34m' ' 35m' '1;35m' \ ' 36m' '1;36m' ' 37m' '1;37m'; do FG=${FGs// /} echo -en " $FGs \033[$FG $T " for BG in 40m 41m 42m 43m 44m 45m 46m 47m; do echo -en "$EINS \033[$FG\033[$BG $T \033[0m"; done echo; done echo } termprop() { infocmp -1 | sed -nu 's/^[ \000\t]*//;s/[ \000\t]*$//;/[^ \t\000]\{1,\}/!d;/acsc/d;s/=.*,//p'| column -c80 } termsupport() { for T in `find "/usr/share/terminfo" -type f -printf '%f\n'`;do echo "$T `tput -T $T colors`" done | sort -nk2 } ## Highlight themes viewer for 256-colors terminals. if [ -f "/usr/bin/highlight" ] ; then hlt-viewer () { print_help() { echo "Synopsis:" echo -e " $1" echo echo "This script displays a preview for every highlight's theme." echo "Press ENTER to display next preview. Press anything else then ENTER to quit." } if [ $# -gt 0 ]; then print_help "$0" return fi local LIST=$(highlight -w | grep -v "\s\|^$") local SAMPLE="void function(char* pointer, int &ref) { int integer=3; char* string=\"Hello!\"; // Line comment for ( i=0; i<10; i++) { printf(\"Sum: %d\\\n\", i*( integer+14 ) ); } }" unset DUMMY for i in $(highlight -w | grep -v "\s\|^$"); do echo "******************** $i ********************" highlight -S c -O xterm256 <(echo $SAMPLE) -s "$i" read -s DUMMY if [ -n "$DUMMY" ]; then return fi done } fi ## Extractor -- Useless when using 'atool'. if [ ! -e "/usr/bin/atool" ]; then extract () { if [ -f $1 ] ; then case $1 in *.tar.bz2) tar xvjf $1 ;; *.tar.gz) tar xvzf $1 ;; *.tar.xz) tar xvJf $1 ;; *.bz2) bunzip2 $1 ;; *.rar) unrar x $1 ;; *.gz) gunzip $1 ;; *.tar) tar xvf $1 ;; *.tbz2) tar xvjf $1 ;; *.tgz) tar xvzf $1 ;; *.zip) unzip $1 ;; *.Z) uncompress $1 ;; *.7z) 7z x $1 ;; *.xz) unxz $1 ;; *.exe) cabextract $1 ;; *) echo "\`$1': unrecognized file compression" ;; esac else echo "\`$1' is not a valid file" fi } fi # Warning: use this function with caution. It may drastically improve # compression of some PDF files, but in some case, the output filesize will be # greater! You should not use it over PDF files embedding pictures as well. pdfcompress () { if [ $# -lt 1 -o $# -gt 2 ]; then echo "Usage: pdfcompress PDFFILE [DESTFILE]" return fi if [ ! -f "$1" ]; then echo "$1 is not a valid PDF file!" fi local INPUTFILE="$1" if [ -z "$2" ]; then gs -dBATCH -dNOPAUSE -q -sDEVICE=pdfwrite -sOutputFile="${INPUTFILE%%.*}-COMPRESSED.pdf" "${INPUTFILE}" rm -rf "${INPUTFILE}" mv "${INPUTFILE%%.*}-COMPRESSED.pdf" "${INPUTFILE}" else local OUTPUTFILE="$2" gs -dBATCH -dNOPAUSE -q -sDEVICE=pdfwrite -sOutputFile="${OUTPUTFILE}" "${INPUTFILE}" fi } pdfextract () { if [ $# -ne 4 ]; then echo "Usage: $0 PDFFILE FIRSTPAGE LASTPAGE DESTFILE" return fi if [ ! -f "$1" ]; then echo "$1 is not a valid PDF file!" fi gs -sDEVICE=pdfwrite -dNOPAUSE -dSAFER -dSAFER -dFirstPage=$2 -dBATCH -dLastPage=$3 -sOutputFile=$4 $1 } ## Create an archive from a single or multiples files/folders. archive () { printhelp() { echo "Synopsis:" echo -e " $1 [-m METHOD] [-v] FILES|FOLDERS" echo echo "Usage:" echo -e " default:\tCreate an archive of specified FILES and/or FOLDERS." echo -e " -h:\t\tDisplay this help." echo -e " -m:\t\tChoose compression method." echo -e " gz\t\tgzip (default)." echo -e " xz\t\tLZMA." echo -e " -v:\t\tInclude VCS data." } local OPTION_VCS="--exclude-vcs" local OPTION_METHOD="" while getopts ":hm:v" opt; do case $opt in h) printhelp "$0" return 1 ;; m) OPTION_METHOD="${OPTARG}" ;; v) OPTION_VCS="" ;; ?) printhelp "$0" return 1 ;; :) echo "Missing argument." echo "Use $0 -h for help." return 1 ;; esac done local ARCEXT local ARCOPT case $OPTION_METHOD in "gz") ARCEXT="tar.gz" ARCOPT="z" ;; "xz") ARCEXT="tar.xz" ARCOPT="J" ;; *) ARCEXT="tar.gz" ARCOPT="z" ;; esac shift $(($OPTIND - 1)) local ARCPATH local ARCSOURCE local ARCNAME if [ $# -eq 1 ]; then ARCPATH="$(dirname $(readlink -f "$1"))" ARCSOURCE="$(basename $(readlink -f "$1"))" ARCNAME="${ARCSOURCE}-$(date +%y-%m-%d-%H%M%S).${ARCEXT}" (cd "$ARCPATH" && \ tar -${ARCOPT} -cvf "$ARCNAME" "$ARCSOURCE" ${OPTION_VCS}) else ARCSOURCE="$(basename $PWD)" ARCNAME="$(basename "$ARCSOURCE")-$(date +%y-%m-%d-%H%M%S).${ARCEXT}" if [ $# = 0 ];then (cd "$PWD/.." && \ tar -${ARCOPT} -cvf "$ARCNAME" "$ARCSOURCE" ${OPTION_VCS}) else ## Note for zsh: do NOT initialize an array with "myarray=()". local FILELIST for i; do FILELIST=(${FILELIST[*]} "$i") done tar -${ARCOPT} -cvf "$ARCNAME" ${FILELIST[*]} ${OPTION_VCS} fi fi } ## Git compare git-compare() { if [ $# -ne 1 ]; then echo "Wrong number of argument." return fi comm -3 <(git ls-files | sort) <(find "$1" -type f | sed 's/^[^\/]*\///g' | sort) } ## This function will clean TeX/LaTeX project folders recursively. texclean () { if [ -z "$1" ]; then WORKDIR="$PWD" else WORKDIR="$1" fi find "$WORKDIR" -type f \( \ -name "*.aux" -o \ -name "*.idx" -o \ -name "*.ilg" -o \ -name "*.ind" -o \ -name "*.lof" -o \ -name "*.log" -o \ -name "*.nav" -o \ -name "*.out" -o \ -name "*.snm" -o \ -name "*.tns" -o \ -name "*.toc" \) \ -print \ -delete } ## Clean current folder vcsclean() { local WORKDIR if [ -z "$1" ]; then WORKDIR="$PWD" else WORKDIR="$1" fi local CHOICE echo "This will clean current folder from all VCS control files." echo -n "Proceed ? [y/N] " while [ -z "$CHOICE" ]; do read CHOICE done CHOICE=$(echo $CHOICE | tr '[:upper:]' '[:lower:]') if [ "$CHOICE" = "y" ]; then find "$WORKDIR" -type d \( \ -name ".bzr" -o \ -name ".cvs" -o \ -name ".git" -o \ -name ".hg" -o \ -name ".svn" \) \ -print \ -delete echo "VCS files cleaned." fi } ## LSOF stats. Print number of open files per process. lsofstat() { local LSOFOUT=$(lsof|awk '{print $1}') for i in $(echo $LSOFOUT |sort -u);do echo -n "$i " echo $LSOFOUT | grep ^$i | wc -l done } ## Format C ## Consider indent, astyle, uncrustify. formatc() { if [ ! -e /usr/bin/indent ]; then echo "Please install 'indent'" return fi local WORKDIR if [ -z "$1" ]; then WORKDIR="$PWD" else WORKDIR="$1" fi find "$WORKDIR" -type f \ -name "*.[ch]" \ -print \ -exec indent -i4 -ppi4 -bli0 -cli4 -nut {} \; ## Remove backup files. find "$WORKDIR" -type f \( \ -name "*.[ch]~" -o \ -name "*.[ch]~[0-9]*~" \) \ -delete # ## Manual method. # ## Remove trailing whitespace # sed -i 's/\s*$//g' "$FILE" # ## Function parenthesis # sed -i 's/\([^ ]\)(/\1 (/g' "$FILE" # sed -i 's/\s\s\+(/ (/g' "$FILE" # ## Semicolon # sed -i 's/\([^ ]\);/\1 ;/g' "$FILE" # sed -i 's/;\([^ ]\)/; \1/g' "$FILE" # # Skip line -- Bad idea because of 'for' loops. # # sed -i 's/^\(\s*\)\(.*\);\s*\(.\+\)$/\1\2;\n\1\3/g' "$FILE" # ## Commas # sed -i 's/\s\s\+,/,/g' "$FILE" # sed -i 's/,\([^ ]\)/, \1/g' "$FILE" # ## Plus/Minus # sed -i 's/\([^+-]\)\([-+]\)\([^ +-]\)/\1\2 \3/g' "$FILE" # sed -i 's/\([^ +-]\)\([-+]\)\([^+-]\)/\1 \2\3/g' "$FILE" # sed -i 's/\( \+++\)/++/g' "$FILE" # sed -i 's/\(++ \+\)/++/g' "$FILE" # sed -i 's/\( \+--\)/--/g' "$FILE" # sed -i 's/\(-- \+\)/--/g' "$FILE" # ## Modulus, equality, affectation, binary ops, comparison # sed -i 's/\s\s\+\(%\|==\|&&\|||\|<=\|>=\|!=\)/ \1/g' "$FILE" # sed -i 's/\(%\|==\|&&\|||\|<=\|>=\|!=\)\s\s\+/\1 /g' "$FILE" # sed -i 's/\([^ ]\)\(%\|==\|&&\|||\|<=\|>=\|!=\)/\1 \2/g' "$FILE" # sed -i 's/\(%\|==\|&&\|||\|<=\|>=\|!=\)\([^ ]\)/\1 \2/g' "$FILE" # ## Equality, >, < # sed -i 's/\s\s\+\([<>=]\)/ \1/g' "$FILE" # sed -i 's/\([<>=]\)\s\s\+/\1 /g' "$FILE" # sed -i 's/\([<>=]\)\([^ =]\)/\1 \2/g' "$FILE" # sed -i 's/\([^ ]\)\([<>]\)/\1 \2/g' "$FILE" # sed -i 's/\([^ =<>]\)\(=\)/\1 \2/g' "$FILE" # ## Asterisk, slash # sed -i 's/\s\s\+\*/ \*/g' "$FILE" # sed -i 's/\*\s\s\+/\* /g' "$FILE" # sed -i 's/\([^\/]\)\/\s\+/\1\//g' "$FILE" # sed -i 's/\s\+\/\([^\/]\)/\/\1/g' "$FILE" # ## Braces # sed -i 's/^\( *\)\(.\+\) *{ *$/\1\2\n\1{/g' "$FILE" # ## Proper comments # sed -i 's:// *\([[:lower:]]\):// \u\1:g' "$FILE" # sed -i 's:\(//.*[^\.]\)$:\1\.:g' "$FILE" } ## This function will try to find an input binary file in the content of binary ## files in current folder. bindatasearch() { if [ $# -eq 0 ] || [ ! -f "$1" ]; then echo "Please provide a valid single file as argument." return fi ## Must be a folder. local TARGET=$PWD if [ $# -eq 2 ] && [ -d "$2" ]; then TARGET="$2" fi ## The awk command suppresses first column, spaces and line breaks. local SOURCE=$(od -tx8 "$1" | awk '($1="")1 gsub ( /\s/,"") { printf ("%s", $0) }') ## This special, not well-known syntax allows us to execute a set of ## functions of the result of find. Since everything MUST be between simple ## quotes, we cannot use external variables directly. So we pass the $SOURCE ## variable as argument. The underscore at the end allow the use of ## arguments. find "$WORKDIR" -type f -exec bash -c ' FILEDUMP=$(od -tx8 "$1" | awk '"'"'($1="")1 gsub ( /\s/,"") { printf ("%s", $0) }'"'"') grep -q "$2" <(echo $FILEDUMP) [ $? -eq 0 ] && echo "$1" ' _ {} "$SOURCE" \; } ## Xrandr xmulti () { if [ $# -ne 1 ]; then echo "Wrong number of argument." return fi xrandr --output "$1" --auto --right-of $(xrandr | sed -n "/current/{n;p;q}" | cut -f1 -d" ") } xmultioff () { if [ $# -ne 1 ]; then echo "Wrong number of argument." return fi xrandr --output "$1" --off } ##============================================================================== ## Pacman Functions ##============================================================================== [ -f "/usr/bin/pacman" ] && . "${SHELL_DIR}/funs_pacman" ##============================================================================== ## FreeBSD Functions ##============================================================================== [ "$(uname)" = FreeBSD ] && . "${SHELL_DIR}/funs_freebsd" ##============================================================================== ## TeXlive functions ##============================================================================== ## TeXlive if [ -d "/usr/local/texlive" ]; then ## Warning: it is important to set umask properly, otherwise users might ## not have authorization to use the packages. ## TODO: It is dirty to invoke a subshell several times. ## Would be better to pass one parameter, then to tokenize it. tli () { for i ; do sudo sh -c 'umask 022 && tlmgr install "$0"' "$i" done } tlr () { for i ; do sudo sh -c 'umask 022 && tlmgr remove "$0"' "$i" done } fi