process a text file line by line
while read -r line; do echo $line done <"filename.txt"
crop image files on the command line
convert -crop +<x>+<y> <sourcefile> <outfile> # crop x pixels from left, y pixels from top convert -crop -<x>-<y> <sourcefile> <outfile> # crop x pixels from right, y pixels from bottom convert <sourcefile> -crop <w>x<h>+<x>+<y> <outfile> # copy out a w*h rectangle (using the letter 'x' instead of '*') starting with top left corner (x, y)
rotate image files on the command line
convert input.jpg -rotate 90 output.jpg find . -maxdepth 1 -type f -name "*.jpg" -exec convert {} -rotate 90 {} \; # bonus - rotate all jpgs in current folder
extract PDF pages as image files
pdftoppm -png -f <first page to extract> -l <last page to extract> <source file>.pdf <output files common prefix>
extract images from PDF
pdfimages <sourcefile>.pdf <basename for all exported images> -png -p
View the label of an ext4 partition
sudo e2label /dev/sdb1/
Relabel an ext4 partition
sudo e2label /dev/sdb1/ backup-a
Initial copy to a backup partition (non-system backup, just my data) / Poor man's rsync
(Don't use rsync for the initial placement of data, it slows down as it goes)
nohup cp -upr /archive/* /media/sean/backup-a/archiveu = update: only copy when destination is older or does not exists
"if... and ..."
if [[ condition 1 ]] && [[ condition 2 ]]; then
"if... or ..."
if [[ condition 1 ]] || [[ condition 2 ]]; then
"declare" - declare a variable as a type, and/or get var info
declare -p myvar # get all kinds of info about the variable declare -a myvar # indexed array declare -A myvar # hash tableRead a file into an array. "-t" means remove trailing delimiter (newline)
mapfile -t myArray < sourcefile.txt
Print out all array values
echo "${myArray[@]}"
Loop through an array.
for i in "${array[@]}"; do echo $i done
Test that an element exists in an array. Just loop through the array. Apparently, there is no built-in array member function for this
for i in "${array[@]}"; do if [[ "$i" == "$yourValue" ]]; then echo "Found" break fi done
Hash tables
declare -A animals animals['cow']='moo' animals["dog"]="arf" echo "${animals["cow"]}"
Hash tables, populate from file
TODO
Get the length of a string
echo ${#mystring}
Increment an int in bash
n="1" ((n++))
Validate correct number of arguments
if [ $# -ne "1" ] then echo "usage myscript <arg1>" exit fi
Validate allowable values for argument
case $1 in "value1") SCRIPTVAR="value1 or some conversion to it" ;; "value2") SCRIPTVAR="value2 or some conversion to it" ;; *) echo "usage: myscript value1|value2" exit esac
Prevent script from running as root
if [ "$(id -u)" -eq 0 ]; then echo "Do not run this script as super-user. Allow the sudos in this script to determine which of the commands should be run as su, and which should be run as sean." exit 1 fi
Strip lines from a file which match a string. Notice that the wildcards go outside the quotes
file="xyz.html" while read -r line; do if [[ $line != *"dont want this line"* ]]; then echo $line > "newfile.html" fi done <$file
Rename files whose names contain a string to filter by
if [ $# -ne 1 ]; then echo "Usage: rename-xyz.sh <filter>" exit fi # Do not quote *$1* when constructing the "for" loop. # This works for file names with spaces as it is. # If you quote, then $F is one long string consisting of # all matching file names concatenated. for f in *$1*; do # newname=$( echo $f | sed 's/[A-Z]/\L&/' ) # rename first char to lower # newname=$( echo $f | sed 's/ \(.\)/\U\1/g' ) # camel-ize a space-separated string (the dot in the escaped parans is a capture group, so we can upper-case it as \1) # newname=$( echo $f | sed 's/[A-Z]/\L&/g' ) # make the whole name lower case if [ "$newname" != "$f" ]; then mv "$f" "$newname" fi done
"convert" image formats, part of the ImageMagick suite of tools, example (I'm not sure what a good value for the quality arg is)
for sourcefile in *.tif*; do basename="${sourcefile%.*}" extension="${sourcefile##*.}" convert "$sourcefile" -compress JPEG -quality 50 "${basename}.jpg" done
get all files whose base name contains only letters
find . -type f -regex '\.\/[a-zA-Z]*\..*'
Split a master flac file into separate tracks using a cue file
Although the flac and cue file are always(?) provided with the same base name, I don't think it's nesessary. What's necessary is for the contents of the cue file to reference the name of the flac file correctly.
cuebreakpoints file.cue | shnsplit -o flac file.flac
wav to flac. The easy and intuitive "flac" command failed on some wav files from Gamazda - didn't like the flac version or something. This is almost as simple and worked for those wav files.
for i in *.wav; do ffmpeg -i "$i" -c:a flac "${i%.*}.flac" done
Take action based on the first character of a string
c1=${name:0:1} if [[ $c1 < "D" ]]; then echo "update hubris.pdfs set link = 'http://www.swordsnwizardry.com/.../all-monsters/monster-details-a-through-c#TOC-$name' where code = 'sw' and creature = '$critter';" elif [[ $c1 = "D" ]]; then echo "update hubris.pdfs set link = 'http://www.swordsnwizardry.com/.../all-monsters/monster-details-d#TOC-$name' where code = 'sw' and creature = '$critter';" ... ... else echo "update hubris.pdfs set link = 'http://www.swordsnwizardry.com/.../all-monsters/monster-details-t-through-z#TOC-$name' where code = 'sw' and creature = '$critter';" fi
Expand critter code (camel format) to probable critter name, capitalized
for f in *"_mycode.pdf"; do # remove _mycode.pdf name=$(echo $f | sed 's/_.*//') # place a space in front of all upper-case chars name=$(echo $name | sed 's/[A-Z]/ &/g') # make the first char upper-case name=$(echo $name | sed 's/[a-z]/\U&/') done
Use perl to replace all links in a string with just the link text -OR- see the next block for easy removel of all tags
Can't use sed because it is always greedy. Adding a "?" after every wildcard group, meaning ".*", keeps perl from making greedy matches.
In the case I used this for, there were sometimes a class name between "<a" and "href=", which is why there is a wildcard group between them
I believe the "-pe" options mean "print" and "execute". The order matters. "-ep" does not work.
strippedhref=$(echo $line | perl -pe 's|<a.*?href.*?>(.*?)</a>|\1|g')
... OR remove all html tags
I believe the "-pe" options mean "print" and "execute". The order matters. "-ep" does not work.
line=$(echo $line | perl -pe 's|<.*?>||g')
Prep a string to be used as an sql statement by escaping single quotes/apostrophes
sql=$(echo $sql | sed "s/'/\\\\'/g")
Given a long string, but not too long, iterate/loop through it based on a delimiter. This cut out after 212 array elements were read.
The weird spacing of the less-thans is due to reading in from a file. If reading in from the string directly,
I think you would use the "here" string construct, which is triple less-thans
IFS='@' read -r -a myArray < <(cat fileConsistingOfOneLongString.txt)
Given one very long string, break into/process substrings with specified delimiter '@'
If the string orignally has a multi-char delimiter, use vim or something to replace it with a single-char delimiter
IFS='@' html=$(cat $f) array=( $html ) for line in "${array[@]}"; do echo $line done
send contents of an sql file to the mysql server
mysql -u sean -pbatman Valor < hb.sql
fetch and process from mysql
export MYSQL_PWD=batman mysql -sN -u sean --execute="SELECT issue FROM Comics.Spiderman;" | while read myissue; do echo "$myissue" done
copy all files in subfolders of a given extension to a destination folder
find . -name \*.html -exec cp {} destinationfolder \;
Extract pages from a pdf file. 2025 version. I don't recall needing the '.' before, but there it is.
In on-line examples, some repeat the full name of the infile in place of the dot.
qpdf infile.pdf --pages . 3-7 -- outfile.pdf