GNU/Linux Command Line

Permission denied errors on settings.php

chmod ug+w web/sites/default

Long-running process

ssh user@server
CTRL-b > d [detach]
ssh user@server
tmux attach

Search for a file with fzf and open with Vim

vi `fzf`

Change files in a directory

rename 's/ /-/g' * && rename 'y/A-Z/a-z/' *

(replace spaces with hyphens and upper case with lower case)

Add a .doc file extension to all files in a directory

rename 's/(.*)/$1.doc/' *

Fix quotation marks

sed -i 's/“/"/g' file && sed -i 's/”/"/g' file && sed -i "s/’/'/g" file && sed -i "s/‘/'/g" file

Upload ssh keys to a server

ssh-copy-id -i ~/.ssh/

Get my IP address


Get battery capacity

sudo tlp-stat -b

Run a command as another user

sudo -u www-data ./occ preview:generate-all -vvv

In the current directory, delete files older than 60 days that don’t end in “15.sql.gz”

find . -not -name "*15.sql.gz" -mtime +60 -exec rm {} \;

Resize an image

convert logo.png -resize 300 logo.png

Optimize an image

[crop image, if necessary]
jpegoptim image.jpg
cwebp -q 60 image.jpg -o image.webp

Get image info

file logo.png

Add text to an image

convert image.jpg -pointsize 64 -font "LMMono12-Regular" -fill white -undercolor Black -annotate +220+70 'Yoga\nRocks!' image-text.jpg

Make a list of ImageMagick font names that can be added to images

convert -list font | grep Font > /tmp/fonts

Convert webp to jpg

dwebp image.webp -o output.png

Create a QR code

qrencode -s 6 -l H -o "matthewtift.png" ""

Create an ico from a image file

icotool -o favicon.ico -c input.png

Crop and resize all images in a directory

mogrify -resize 1280x720^ -gravity center -extent 1280x720 *.jpg

(gravity could also take values like North, NorthWest, or East)

Resize an image, keep aspect ratio, and fill blank space

convert input.jpg -resize 1280x720 -background white -gravity center -extent 1280x720 output.jpg

Rename all .jpg files in a directory sequentially

ls | grep "\.jpg$" | cat -n | while read n f; do mv "$f" `printf "image%03d.jpg" $n`; done

Rename files in a directory starting with 15

num=15 && for file in *.mp3; do mv "$file" "sound-file-$(printf "%03d" $num).mp3"; let num=$num+1; done

Prepend all .mp3 files in a directory with a 3-digit number

ls | grep "\.mp3$" | cat -n | while read n f; do mv "$f" `printf "%03d-$f" $n`; done

Update the title of a PDF

exiftool -Title="New Title" /path/to/filename.pdf

Add a signature to a PDF

xournal document.pdf
tools >> image >> click in document >> select image

Password protect a PDF

pdftk source.pdf output destination.pdf user_pw PROMPT

Send a notification (pop-up) after a process is complete

drush mim migrate_nodes; notify-send "Node migration complete"

Spin up a Drupal 8 site

cd /var/www
mkdir drupal && cd drupal && curl -sSL | tar -xz --strip-components=1
php ./core/scripts/drupal quick-start standard

Drupal core workflow

git apply --index issue.patch
git diff > interdiff.txt
git diff HEAD > new.patch

Create a patch file that removes a binary file in Git

rm image.png
git diff --binary > issue.patch

Compare files changed in my branch to master

git diff master my-branch --name-only

Update default browser in Debian

sudo update-alternatives --config x-www-browser

Convert Unix timestamp on the command line

date -d @$TIMESTAMP

Get current time in something like PBS Changelog format

date -u +%Y-%m-%dT%H:%M:%S.%N

Find and edit

grep -rl 'hook_expire_cache_alter' . | xargs gvim -p

Find and replace

grep -rl 'OLD_TEXT' . | xargs sed -i 's/OLD_TEXT/NEW_TEXT/g'

Download high quality audio from YouTube (best quality is 0)

youtube-dl --extract-audio --audio-format wav --audio-quality 0 URL

Crop/cut a video

9 minutes and 20 seconds of a video starting at 1 minute and 30 seconds

ffmpeg -i input.mp4 -ss 00:01:30 -t 00:09:20 part1.mp4
ffmpeg -i input.mp4 -ss 00:01:30 -to 00:10:50 part1.mp4

14 minutes and 20 seconds of the top left part of a video, starting at 18 seconds

ffmpeg -i video1996041126.mp4 -ss 00:00:18 -to 00:14:38 -filter:v "crop=640:360:0:0" output.mp4

Crop the left half of a Zoom video starting at 7 seconds and ending at 30:25:

ffmpeg -i LF2023-12-17.mp4 -ss 00:00:07 -to 00:30:25 -filter:v "crop=1600:960:0:0" output.mp4

Combine audio with one file with the video from other file

ffmpeg -i INPUT_FILE.mp4 -i AUDIO.mp3 -c:v copy -c:a copy -map 0:v:0 -map 1:a:0 OUTPUT_FILE.mp4

Get “Date Taken” times of JPGs in a directory

exiv2 *.JPG | grep "Image timestamp"

Change “Date Taken” times of JPGs in a directory

exiftool "-AllDates=2002:01:01 04:00:00" *.JPG

Find Files 100-999M

du -h | grep '[0-9]\{3\}M'

Make PDFs searchable

ocrmypdf file.pdf file.pdf


Log arrays with logger in Drupal 8

\Drupal::logger('Matthew')->notice('<pre><code>' . print_r($variable, TRUE) . '</code></pre>');

Debug JS in PHP code

echo "&lt;script type='text/javascript'&gt; alert(" . print_r($var) . "); &lt;/script&gt;";

Pass array as command line argument

php -r "print json_encode(array('node/*/edit' =&gt;
'128M', 'node/add/type' =&gt; '128M'));" |
drush vset --format=json page_memory_limit -

Export var_dump json responses to a file to open with Firefox

$fp = fopen('/tmp/results.json', 'w');
fwrite($fp, json_encode($response));


Get Size of All MySQL Databases

SELECT table_schema "DB Name",
Round(Sum(data_length + index_length) / 1024 / 1024, 1) "DB Size in MB"
FROM information_schema.tables
GROUP BY table_schema;

Stop Drupal cron using MySQL (via drush)

drush sqlq "DELETE FROM semaphore WHERE name = 'cron';"

Delete all files in a Drupal database

TRUNCATE file_managed;
TRUNCATE file_usage;


Count words in Vim

g > CTRL-g

Wrap text


Delete blank lines in Vim


Vim special characters (didigraphs)

CTRL-k a - (ā)
CTRL-k a ! (à)
CTRL-k n . (ṅ)
CTRL-k e ' (é)
CTRL-k u - (ū)
CTRL-k u : (ü)
CTRL-k D G (°, the degree character)

Paste into the Vim command line

CTRL-r +

Remove ^M characters at end of lines

%s/[CTRL-V CTRL-M]//g

Jump to the class under the cursor


Jump back


Surround 1 word with a single quote


Surround 2 words (separated by a space) with asterisks


Swap text around equal sign

:%s/\([^=]*\)\s\+=\s\+\([^;]*\)/\2 = \1

Generate number lines

Insert "0. " for each line that needs a number
"CTRL-V" to select each line
"g CTRL-a" to replace the numbers with a sequence

Format XML

! xmllint --format -