Useful CLI commands

From Reboil

These are mostly Debian GNU/Linux command line interface commands.




Part of the colorized-logs Debian package.

Remove color codes from text.[1]

 $ ansi2txt < ./input.txt > ./output.txt


Check which packages depend on package package-name.[2]

$ apt rdepends package-name

Install upgrades without prompts[3]

$ sudo DEBIAN_FRONTEND=noninteractive apt upgrade -y


Calculate MD5 checksum of a binary file.[4]

$ openssl md5 -binary foo.txt | base64  # with openssl and base64
$ md5sum --binary foo.txt | cut -d' ' -f1 | xxd -r -p | base64  # with md5sum, xxd and base64[5]



Search find results with grep using the exit code from a statement evaluated by the built-in if.

$ mkdir a;
$ touch ./a/foo.txt
$ touch ./a/bar.txt
$ if results="$(find . -type f | grep 'foo')"; then printf "Found:\n%s\n" "$results"; else printf "Found nothing.\n"; fi;
$ if results="$(find . -type f | grep 'baz')"; then printf "Found:\n%s\n" "$results"; else printf "Found nothing.\n"; fi;
Found nothing.
$ if results="$(find . -type f | grep '.txt$')"; then printf "Found:\n%s\n" "$results"; else printf "Found nothing.\n"; fi;

Use modulo integer math to print the integers between 0 and 100 that are divisible by 5.

for ((i=0; i<=100; i++)); do
  if [ $((i % 5)) -eq 0 ]; then
    echo $i

Count the number of occurrences of a single ASCII character (e.g. ,) (see ref)

echo "$res"
echo "${#res}"

Bash input/output

Provide string to a command via stdin. The following are equivalent.

$ echo "666" | sed 's/6/7/g';              # Uses pipe format.
$ myVar="666"; sed 's/6/7/g <<< "$myVar";  # Uses “here string” format.[6]

Bash job management


Push job into background.

^Z   # (i.e. Ctrl-Z)
[1]+ Stopped     git tag --sign 2023-04-15 -m "SignStamp state" 6e31b1a

Get a list of current background jobs

$ jobs
[1]+ Stopped     git tag --sign 2023-04-15 -m "SignStamp state" 6e31b1a

Restart a job (e.g. one with jobspec 1) in the background and check that it is running.

$ bg 1
[1]+ git tag --sign 2023-04-15 -m "SignStamp state" 6e31b1a &
$ jobs
[1]+ Running     git tag --sign 2023-04-15 -m "SignStamp state" 6e31b1a &

Detach a job (e.g. one with jobspec 1) from the current shell to permit safe exit without terminating the job.

$ disown %1

Bash string manipulation

See Manipulating Strings.

Replace substring in variable.[7]

$ myVar="foobarbaz";
$ echo "${myVar/bar/qux}";

Get first 7 characters of a string.

$ myVar="deadbeef";
$ echo "${myVar:0:7}"

Get last 4 characters of a string.

$ myVar="deadbeef";
$ echo "${myVar:(-4)}";


Evaluate math expressions

$ echo "scale=12; 1 / 1.61803398875" | bc -l
$ echo "scale=6; l(2.718281)" | bc -l



Remove read, write, and execute permissions for others to a file or directory named foo.

# chmod o-rwx foo

Add read and execute permissions for group to a file or directory named foo.

# chmod g+rx foo

Make all directories openable (i.e. executable) by user starting at a directory named bar.

# find ./bar -type d -exec chmod u+x \;

Make all files non-executable by everyone within a directory named bar.

# find ./bar -type f -exec chmod ugo-x \;
# find ./bar -type f -exec chmod -x \;

Make a file named foo executable for user, group, and others (i.e. everyone).

# chown +x foo


Get OOM score for process with PID 1

$ choom --pid 1

List the bottom 50 processes in the OOM priority list (during low memory, the bottom is killed first).

$ printf "pid,ooms,name\n"; while read -r line; do pid="$(echo "$line" | cut -d' ' -f2)"; name="$(echo "$line" | cut -d' ' -f11-)"; ooms="$(choom -p "$pid" | grep -Eo "[0-9]+$" | head -n1)"; printf "%9d,%4d,%s\n" "$pid" "$ooms" "$name"; done < <(ps aux | tr -s ' ' | tail -n+2) | sort -k2 | tail -n50


Change ownership of a file or directory named baz to user debuser and group debuser.

# chown debuser:debuser baz

Change ownership of all files and directories contained within the directory named foo to user debuser and group debuser.

root@h: chown -R debuser:debuser foo


The following commands assume the package chrony is installed.

Get a list of NTP refclocks being used to adjust local time:

$ chronyc sources

Get current machine's statistics (e.g. get Frequency or how slow or fast local clock is)

$ chronyc tracking


See #ImageMagick


Edit crontab.

$ crontab -e

Print crontab to stdout:

$ crontab -l


$ crontab -r

Print to stdout the crontab of user www-data via user root (ref):

$ sudo su - www-data -s /bin/bash -c "crontab -l"


Get details on a volume encrypted with LUKS

$ cryptsetup status /dev/mapper/$some_volume

where $some_volume is the name of an encrypted volume. Reference.


Note: Assumes GNU date.

Print today's calendar date in ISO 8601 format

$ date -I
$ date -Id
$ date +%Y-%m-%d

Print current date and time in ISO 8601 format to second resolution.

$ date -Is                    # e.g. 2024-02-01T05:44:58+00:00
$ date +%Y-%m-%dT%H:%M:%S%:z  # e.g. 2024-02-01T05:44:58+00:00

Print current date and time in ISO 8601 format to second resolution with minimal separators. (e.g. for file name use)

$ date +%Y%m%dT%H%M%S%z  # e.g. 20240201T054458+00

Print current UNIX epoch. (i.e. integer seconds since 1970-01-01.)

$ date +%s

Print all calendar dates for the next 365 days. (e.g. 2024-02-01\n2024-02-02\n2024-02-03\n…)

today="$(date +%s)"; n=0; for dia in {0..365}; do
  day="$((today + dia * (24*60*60) ))";
  date --date="@$day" "+%Y-%m-%d";


Read every block of a block device /dev/sdb in 4 KiB increments.

$ sudo dd if=/dev/sdb of=/dev/random bs=4k

Create a 10 MiB file containing pseudorandom noise using 2 MiB of RAM at a time.[8]

$ dd if=/dev/urandom of=sample.txt bs=2M count=5


Get public IP address[9]:

$ dig +short
$ dig +short txt ch whoami.cloudflare @
$ dig TXT +short


List available kernels.

$ dpkg --list | grep -- linux-image

Check which package owns a file.

$ dpkg -S /etc/systemd/logind.conf  # by file path
$ dpkg -S "$(which zdump)"          # by command name, e.g. `zdump`


Add a locale in Debian-based systems that use dpkg.

$ sudo dpkg-reconfigure locales
Navigate menus to select the local. Recommended: locales ending in .UTF-8 (e.g. C.UTF-8 (compatibility), en_US.UTF-8 (English of United States), zh_CN.UTF-8 (Chinese of mainland China), id_ID.UTF-8 (Indonesian of Indonesia), ja_JP.UTF-8 (Japanese of Japan), ko_KR.UTF-8 (Korean of South Korea).


Consider using dool (GitHub)

Show system stats, averaged every 60 seconds per line

 dstat --time --load --proc --cpu --mem --disk --io --net --sys --vm 60


See Emacs notes


Note: Consider using BK-2020-03bkphotorights script to add XMP data with Creative Commons attribution data.

List all exif data, including XMP tags.

$ exiftool file.jpg

Remove all exif data from photograph files

$ exiftool -all= file.jpg

Remove only GPS exif data from JPG (see )

$ exiftool -gps:all= file.jpg

remove only GPS exif data from JPG If GPS is in XMP:

$ exiftool "-gps*=" file.jpg


Extract clip with time codes.

$ ffmpeg -i input.mp4 -ss 00:01:00.000 -to 00:03:00.000 -avoid_negative_ts 1 output.mp4
$ ffmpeg -i input.mp4 -ss 00:01:00.000 -to 00:03:00.000 -c:v libx264 -preset slow -crf 18 -c:a aac -b:a 128k -avoid_negative_ts 1 output.mp4      

Extract frame of video to save as PNG file (e.g. the first frame).

$ ffmpeg -i input.webm -ss 00:00:00 -frames:v 1 output.png

Extract album artwork from one of the original audiobook mp3 files. (see Audiobook transcoding notes.)

$ ffmpeg -i How\ To\ -\ Track\ 001.mp3 -an -vcodec copy album_artwork.png

Encode video

Encode video using VP9 codec with 2 passes and tile-based multithreading.[10]

ffmpeg -nostdin -i "$fin" -c:v libvpx-vp9 -row-mt 1 -b:v 0 -crf 18 -pass 1 -f null /dev/null && \
ffmpeg -nostdin -i "$fin" -c:v libvpx-vp9 -row-mt 1 -b:v 0 -crf 18 -pass 2 "${fin%.mkv}.webm"

Specify a constant rate factor (CRF)

$ ffmpeg -i input.mp4 -c:v libx264 -preset slow -crf 18 -c:a copy output.mp4

Clip a video at CRF 18 and encode audio to OPUS.

$ ffmpeg -i input.mp4 -ss 00:01:00.000 -to 00:03:00.000 -c:v libx264 -preset slow -crf 18 -c:a libopus -b:a 128k -avoid_negative_ts 1 output.mp4

Process multiple videos in a Bash while loop. (Avoid stdin conflict with -nostdin option)[11][12]

while IFS= read -r file; do
  ffmpeg -nostdin -i "$file" -c:v libx264 -c:a aac "${file%.avi}".mkv
done < <(find . -name '*.avi')

Split a video file into roughly equal segments


$ ffmpeg -i input.mp4 -c copy -map 0 -segment_time 00:20:00 -f segment -reset_timestamps 1 output%03d.mp4

Combine video files into a single file


# this is a comment of the file named mylist.txt
file '/path/to/file1.wav'
file '/path/to/file2.wav'
file '/path/to/file3.wav'
ffmpeg -f concat -safe 0 -i mylist.txt -c copy output.wav

Add subtitles to a video file

Add multiple ASS subtitle files to a single MP4 video file.[13]

ffmpeg -i input.mp4 \
       -sub_charenc 'UTF-8' -f ass -i input.en-US.ass \
       -sub_charenc 'UTF-8' -f ass -i \
       -sub_charenc 'UTF-8' -f ass -i \
       -sub_charenc 'UTF-8' -f ass -i input.ja.ass \
       -map 0:v -map 0:a \
       -map 1 -map 2 -map 3 -map 4 \
       -metadata:s:s:0 language=eng \
       -metadata:s:s:1 language=spa \
       -metadata:s:s:2 language=ind \
       -metadata:s:s:3 language=jpn \
       -c copy \
       -c:s ass output.mkv


Get audio duration in seconds as a decimal number.[14]

$ ffprobe -i "$file" -show_entries format=duration -v quiet -of csv="p=0";
Get audio duration in seconds of all .flac files in the working directory with bc.
dur="0.0"; while read -r line; do
  line_dur="$(ffprobe -i "$line" -show_entries format=duration -v quiet -of csv="p=0")";
  dur="$(echo "$dur + $line_dur" | bc -l)";
done < <(find . -type f -name "*.flac");
echo "$dur";

Get chapter times.[15][fn 1]

$ ffprobe -i "$file" -print_format json -show_chapters -sexagesimal


Outputs newline-delimited (default) list of paths of files or directories matching specified filters.

List all files recursively

$ find . -type f

List all directories recursively

$ find . -type d

Search $HOME for files ending in .jpg or .JPG.

$ find $HOME/ -type f -iname "*.jpg"

Get file sizes, via du, of all files recursively

$ find . -type f -exec du -b '{}' \;

List all files and directories within one level of subdirectories

$ find . -maxdepth 1

List all files and directories precisely 4 subdirectories deep

$ find . -mindepth 4 -maxdepth 4

List all files recursively, following symlinks up to a maximum depth of 10 subdirectories deep

$ find -L . -maxdepth 10 -type f

List all files and directories starting with a . (i.e. list all dotfiles and dotdirs)

$ find . -name ".*"

List all files and directories starting with a .

$ find . ! -name ".*"

List all files recursively except those ending in either .ots or .ots.bak

$ find . -type f ! \( -name "*.ots" -or -name "*.ots.bak" \)

Find files of a minimum size. (e.g. greater than but not equal to 1 MiB)

$ find . -type f -size +$((1024 * 1024))c  # calc MiB
$ find . -type f -size +$((1024 ** 2))c    # calc MiB
$ find . -type f -size +1048576c           # use bytes
$ find . -type f -size +1M                 # do not use due to rounding issues

Find files of a maximum size. (e.g. less than but not equal to 1 MiB)

$ find . -type f -size -1048576c  # use -1048576c instead of -1M due to rounding issues


The GNU C Compiler

Compile C-code specified in the command line.[16]

$ gcc -x c <(echo 'int main(){return 0;}')
$ echo 'int main(){return 0;}' | gcc -x c -
$ gcc -x c -o hello <(echo -e "#include <stdio.h>\n main()\n{\nprintf(\"hello, \");\nprintf(\"world\");\nprintf(\"\\\n\");\n}")


See recent checkout, commit, or other operations by commit reference. (e.g. to find a commit lost because it was on a detached HEAD).

$ git reflog

To automatically sign merges (not default).

$ git config merge.gpgsign true
$ git -c merge.gpgsign='true' pull

See remotes.

$ git remote -v

Rename a remote. (ref)

$ git remote rename beanstalk origin

Export a git bundle (repository backup)

$ git bundle create filename.bundle --all

Trace git operations (especially those involving gpg signing operations). (ref)

$ GIT_TRACE=1 git commit

Get current commit, short git log entry, and ISO-8601 date

$ git log -1 --pretty=format:"%h %s %cd" --date=iso
$ git log -1 --pretty=format:"%h %s %cd" --date=format:"%Y-%m-%d"  #shorter date

Delete a local branch named `develop` (assuming `develop` is not checked out).

$ git branch -d develop

Untrack but don't remove committed file. (Ref/attrib; useful if you tracked something that shouldn't be tracked like repo.git/config)

$ git rm --cached path/to/committed/file

Pull branch develop from remote origin to unchecked out local branch develop without altering working tree (useful if worktree files are being used by something else).

$ git pull origin develop:develop

Set single configuration parameters for the duration of a single command.

Disable checking GPG signatures when running $ git log. (see ref)
$ git -c log.showSignature='false' log
Commit and/or tag with ots --wait option.
$ pathOtsWait="/home/debuser/.local/share/ots/";
$ git -c gpg.program="$pathOtsWait" commit -S
$ git -c gpg.program="$pathOtsWait" tag --sign "some_tag_name" main

Set a remote branch `origin/develop` as the upstream branch for a local branch named `develop`.[17]

$ git branch --set-upstream-to=origin/develop develop

Get current commit, short git log entry, and ISO-8601 date

$ git log -1 --pretty=format:"%h %s %cd" --date=iso
$ git log -1 --pretty=format:"%h %s %cd" --date=format:"%Y-%m-%d"  #shorter date

Delete a local branch named `develop` (assuming `develop` is not checked out).

$ git branch -d develop

Untrack but don't remove committed file. (Ref/attrib; useful if you tracked something that shouldn't be tracked like repo.git/config)

$ git rm --cached path/to/committed/file

Pull branch develop from remote origin to unchecked out local branch develop without altering working tree (useful if worktree files are being used by something else).

$ git pull origin develop:develop

Set a remote branch `origin/develop` as the upstream branch for a local branch named `develop`.[17]

$ git branch --set-upstream-to=origin/develop develop

Disable git credential helper for a single command.[18]

$ git -c credential.helper= pull origin refs/heads/master


See also GnuPG

Use a temporary keyring

$ gpg --no-default-keyring --keyring /dev/shm/temp-keyring.kbx

Refresh keys

$ gpg --keyserver --receive-keys deadbeef deadbeef
$ gpg --keyserver --receive-keys deadbeef deadbeef


Search for a process named “bash” with ps aux and grep bash but exclude matches of “grep bash" itself.

$ ps aux | grep "bas[h]"

Ignore binary matches with -I option.

$ grep "a" largeProgram.exe && echo "Match found." || echo "No match found."
grep: get_put_char: binary file matches
Match found.
$ grep -I "a" largeProgram.exe && echo "Match found." || echo "No match found."
No match found.

Use find with parallel to recursively search a file tree for text matches.

$ find . -type f -name "*.tsv" | parallel grep -iHIC3 --color=always -e 'mexico' '{}'
-name "*.tsv": Search only files with names ending in .tsv.
-i: Ignore character capitalization.
-H: Print name of file containing match.
-C3: Show 3 lines before and after match.
-I: Do not search binary files.
-e 'mexico': Search for lines containing the string mexico
'{}': Filename word placeholder for parallel.


See also Ghostscript.

Remove raster images from a PDF.[19]

 $ gs -o noimages.pdf -sDEVICE=pdfwrite -dFILTERIMAGE input.pdf

Regular Expressions

Show lines that match pattern.

$ grep 'some pattern' -- file.txt

Show lines that don't match pattern.

$ grep -v 'some pattern' -- file.txt

Match integers of a range of numbers of digits (e.g. 2 to 3)

$ myVar="$(printf "S2 E3\nS57 E11\nS131 E51\nS7212 E3\n")"
$ echo "$myVar"
S2 E3
S57 E11
S131 E51
S7212 E3
$ echo "$myVar" | grep -E "S[0-9]{2,3} "
S57 E11
S131 E51

Match http URLs in a text file (see ref)

$ cat input.txt | grep -Eo "(http|https)://[a-zA-Z0-9./?=_%:-]*" | sort -u


See #gzip.


Transform a sql.gz archive into a sql.xz archive.

$ gunzip -c archivo.sql.gz | xz -z - > archivo.sql.xz


Show data traffic (i.e. bandwidth usage) on network interface eth0. Note: consider using in tandem with nethogs.

$ sudo iftop -i eth0


Show disk write rates for a given process by PID.

$ iotop -p PID

List accumulative (-a) disk read/write rates for all tar and xz processes via process PIDs (-p), updating every 10 seconds (-d10).

$ sudo iotop -ad10 $(pgrep "tar|xz" | xargs -I "{}" echo -n "-p {} ")


Show available network interfaces.

$ ip link show


Convert a PNG file into a JPEG at 90% quality.

 $ convert input.png -quality 90 output.jpg

Convert a GIF into a set of frames (Note: May fail with some optimized GIF formats)

$ convert Year_2038_problem.gif output%02d.gif


List duplicates in DIR greater than or equal to 100MB.

$ jdupes -X size+=:100MB DIR -r

List duplicates within DIR1 (not following subdirectories) and within DIR2 (following subdirectories)

$ jdupes -X size+=:100MB DIR1 -R DIR2

List duplicates within DIR1, DIR2, and DIR3 recursively, listing duplicates of DIR1 first

$ jdupes -r -O DIR1 DIR2 DIR3


Show previous 1 hour of logs:

$ journalctl --utc --all --output=short-iso --since=-1h

Show logs since 2023-01-10T09:15 and before 2023-01-10T13:00:

$ journalctl --utc --all --output=short-iso --since=\"2023-01-10 09:15\" --until=\"2023-01-10 13:00\"


Display file as scrollable buffer..

$ less file.txt

Display file and display live updates.

$ less +F file.txt

Display file while truncating display of long lines.

$ less -S file.txt

Display file while interpreting ANSI color codes (e.g. $ jq -C '.' file.json | less --RAW-CONTROL-CHARS)



Display all files opened by a process by a single PID.[20]

$ lsof -p PID

Display all files opened by a process by name (e.g. xz)[20]

$ while read -r line; do lsof -p "$line"; printf "\n"; done < <(pgrep xz)




$ mail   # start mail
& h$     # list latest messages[21]
& 5      # read message 5
& d 1    # delete message 1
& q      # quit mail

Send mail to self:

$ mail -s "I'm in your base" -- "$(whoami)" < <(printf "Killing your dudes.\n")

Delete all mail[22]:

$ mail -N
& d *
& quit


See GNU Make

Compile source code according to a file named Makefile

$ make

Note, even with GNU make, column 1 indentations REQUIRE a tab (i.e. `\t`), not a space (`\s`).[23]

Compile multiple source code files with a single `make all` command.[24] `Makefile` contents:

all: program1 program2

program1: program1.c
    gcc -o program1 program1.c

program2: program2.c
    gcc -o program2 program2.c


Software RAID manager.

Check status of RAID device /dev/md0.[25]

$ sudo mdadm --detail /dev/md0

Check status of all RAID devices.[25]

$ sudo cat /proc/mdstat


Get file mimetype

$ cat file.jpg | mimetype --stdin


Use newline-delimited stdin list of file paths as playlist.

$ find ~/Music/ -type f | mpv --playlist=-

Enable shuffle

$ mpv --shuffle

Settings for fast playback (e.g. 2x)

$ mpv --af=scaletempo=stride=15:overlap=1:search=15'

Play video with subtitle file

$ mpv --embed-subs="$filepath" video.mp4


Show system information without art

$ neofetch --off


Show data traffic (i.e. bandwidth usage) by process on network interface eth0.

$ sudo nethogs eth0


Note (Debian): Installed via the libnotify-bin package.

Create a system notification:

$ notify-send "title" "body"


Convert markdown text file into mediawiki code.[26]

$ pandoc -f markdown -t mediawiki -o output.wc input.txt


Create parity files of archive.tar.xz with default settings.

$ par2 create archive.tar.xz.par2 archive.tar.xz


See GNU parallel

Duplicate a set of directories (non-recursively) (e.g. home sub-directories). Metadata not copied.

$ find "$HOME" -mindepth 1 -maxdepth 1 -type d | parallel mkdir "$HOME/{}"

Hash every file in the home directory.

$ find "$HOME" -type f | parallel --jobs="" sha256sum '{}'               # use all CPUs
$ find "$HOME" -type f | parallel --jobs="25%" sha256sum '{}'  # use at most 25% of CPU cores
$ find "$HOME" -type f | parallel sha256sum '{}'               # 

Run a thread for every item in an array.

$ myArray=("jan"); myArray=("feb"); myArray=("mar");
$ declare -p myArray
declare -a myArray=([0]="jan" [1]="feb" [2]="mar")
$ parallel echo '{}' ::: "${myArray[@]}"


Show process PIDs and full commands.

$ ps -eo pid,args


Combine PDFs

 $ pdftk doc1.pdf doc2.pdf doc3.pdf cat output output.pdf


Exit early if a specific process (e.g. yt-dlp) is already running.

 $ if pgrep "yt-dlp" 1>/dev/random 2>&1; then exit 1; fi;


GNU Coreutils

Round a float to nearest integer[27]:

 $ myVar="14.28571"; printf "%.0f\n" "$myVar";
 $ myVar="14.28571"; printf "%.2f\n" "$myVar"
 $ myVar="14.28571"; printf "%.1f\n" "$myVar"
 $ myVar="-14.28571"; printf "%.2f\n" "$myVar"
 $ myVar="28.57142"; printf "%.2f\n" "$myVar"
 $ myVar="28.57142"; printf "%.0f\n" "$myVar"
Note, GNU Coreutils printf uses “round to even” (i.e. “Bankerʼs rounding”) for cases when 5 must be rounded.[28]
 $ myVar="5.5"; printf "%.0f\n" "$myVar"
 $ myVar="6.5"; printf "%.0f\n" "$myVar" 
 $ myVar="7.5"; printf "%.0f\n" "$myVar"
 $ myVar="8.5"; printf "%.0f\n" "$myVar" 

Print integer with leading zeroes. (see ref)

$ n=7; printf "%05d\n" "$n";

Print a bash array (see ref)

$ declare -a my_array; my_array+=("jan"); my_array+=("feb");
$ printf '%s\n' "${my_array[@]}";

Print a progress bar



while [ $current_iteration -lt $total_iterations ]; do
    # Your actual loop content goes here
    sleep 0.1 # This is just an example, replace with your actual task

    # Calculate progress percentage
    progress_percentage=$(( 100 * current_iteration / total_iterations ))

    # Print progress percentage without causing scrolling
    printf "\rProgress: %3d%%" $progress_percentage

    # Increment the iteration counter
    current_iteration=$(( current_iteration + 1 ))

# Print a newline character to move to the next line after the loop is done

C stdio.h

Print an int as a hexadecimal

int a=17; printf("%x\n",a);

Print an int as a binary (glibc >2.35, check via $ ldd --version)

#include <stdio.h>
int main()
  int a=1023; printf("%b\n",a); return 0;
When compiled with gcc-12 (previous versions throw errors) and glibc >2.35, this prints:


Get a counted list of unique file extensions in the current working directory.

$ find ./ -type f | rev | cut -d'/' -f1 | cut -d'.' -f1 | rev | sort | uniq -c | sort -hk1;
An explanation:
$ find ./ -type f | \  # Get a list of files in current working directory.
  rev | \              # Reverse order of characters within each line.
  cut -d'/' -f1 | \    # Get file name.
  cut -d'.' -f1 | \    # Cut all characters except for those before the final `.` in the filename.
  rev | \              # Restore order of characters within each line.
  sort | \             # Sort for uniq.
  uniq -c | \          # Count and remove duplicates.
  sort -hk1;           # Sort by extension count field of each line.


Note: These commands assume use of rsync version 3.2.7 protocol version 31, which is available on Debian version 11.

Exclude all dotfiles or dotdirectories at any directory level.

$ echo ".*/**" >> exclude.txt
$ rsync -avu --exclude-from=exclude.txt somepath/SOURCE/ anotherpath/DEST/

Copy all files contained within a directory named SOURCE located within somepath into a directory named DEST within anotherpath, preserving file attributes (e.g. user:group, read/write/execute permissions), and overwriting existing files within DEST if they differ in modification date and/or size from those of SOURCE. The forward slashes after SOURCE and DEST are significant; omitting them may cause the creation of a new directory layer instead of synchronizing the file trees of SOURCE and DEST.

$ rsync -avu somepath/SOURCE/ anotherpath/DEST/

Make the contents of DEST exactly match that of SOURCE, overwriting and deleting files as required in DEST via the --delete-before command, performing all deletions before file copying begins. This is useful for updating a backup of SOURCE at DEST.

$ rsync -avu --delete-before somepath/SOURCE/ anotherpath/somedir/DEST/

Copy files from a local SOURCE to a DEST in a remote user's home directory (e.g. /home/username/DEST/) via the ssh command.

$ rsync -avu -e 'ssh' somepath/SOURCE/ username@hostname:DEST/

Copy files only files containing _small in their filenames from a SOURCE to DEST. This preserves the directory tree of SOURCE.

$ rsync -avu --progress --include '*/' --include '*_small*' --exclude '*' somepath/SOURCE/ somepath/DEST/
Move only the files containing _small in their file names, deleting them from SOURCE if successfully copied to DEST.
$ rsync -avu --progress --include '*/' --include '*_small*' --exclude '*' --remove-source-files somepath/SOURCE/ somepath/DEST/

Recreate full path at destination.[29]

$ rsync -avu -R somepath/SOURCE/ anotherpath/DEST/
$ ls anotherpath/DEST/somepath/SOURCE/


GNU sed manual.

Replace first instance of a string.

$ echo "foo foo" | sed 's/oo/ee/'
fee foo

Replace all instances of a string.

$ echo "foo foo" | sed 's/oo/ee/g'
fee fee

Replace all instances of a string in a file (CAUTION: modifies the file):

$ printf "foo\n" > bar.txt
$ cat bar.txt
$ sed -i 's/oo/ee/g' bar.txt
$ cat bar.txt

Append something to the start of each line (ref):

$ printf "bar\nbaz\n" | sed 's/^/foo/'
$ printf "bar\nbaz\n" | sed 's~^~foo~'   # use ~ instead of / as regex delimiter

Delete blank lines. (see ref)

$ printf "foo\n\nbar\n"

$ printf "foo\n\nbar\n" | sed '/^$/d'

Remove an initial `./` from the start of file lists produced by `find` whether newlines or NULL chars are used as list delimiters. Example: sumdir v0.1.2

$ sed -E 's/(^|\x00)\.\//\1/g'

Print specific lines of a file. (i.e. get a specific line from a file)

$ some_command | sed -n '2p'  # prints line 2 of standard input
$ sed -n '2p' file.txt        # prints line 2[30]
$ sed -n '2q;d' big_file.txt  # prints line of a very large file.[31]
$ sed -n '2p;'
$ sed -n '2,5p' file.txt      # prints lines 2 through 5 inclusive.
$ sed -n '2;5;' file.txt      # prints only lines 2 and 5.


Connect to a local machine's Syncthing instance via firefox.

$ firefox

Connect to a remote server's Syncthing instance via ssh port forwarding and firefox.

$ ssh -L user@hostname
$ firefox

Get a host's SSH fingerprint[32]

$ ssh-keygen -l -f /etc/ssh/


Sort part of a checksum file while ignoring some initial lines (e.g. a checksum file generated by sumdir). Sorts every line except for the first three lines which it leaves at the top; the output is written to /tmp/0.txt. Uses the -k2 (i.e. "key 2") option of sort which says to sort by the file name, not the hash (hash is first whitespace-separated entry, file name is the second).

file=.SUMSHA256--20230126T050458+0000; ( cat "$file" | head -n3; cat "$file" | tail -n+4 | sort -k2; ) > /tmp/0.txt

Sort on the third field of comma-delimited lines

$ printf "1,foo,kobo\n2,bar,kaela\n3,baz,zeta\n" | sort -t',' -k3

Remove duplicate lines without sorted result (preserving first copied unique line). (see ref)

$ myVar="$( printf "gundam\ninuyasha\ngundam\nbleach\ngundam\nnaruto\ngundam\n" )"
$ echo "$myVar" | cat -n | sort -uk2 | sort -n | cut -f2-
Preserving last unique copied line.
echo "$myVar" | tac | cat -n | sort -uk2 | sort -n | cut -f2- | tac


A GNU Coreutils program that controls how stdin, stdout, and error data is passed in and out of a program.

Read input from stdin and pass through output to stdout without any buffering.[33]

$ stdbuf -i0 -o0 -e0 command
Example: Continuously filtering journalctl output to capture apache-access lines while discarding the first 7 space-delimited fields of each line. If stdbuf is not used in this type of scenario, tr and cut may fail to immediately display important lines as they arrive from journalctl, choosing to wait until a buffer is filled before displaying them (defeating the purpose of the --follow option of journalctl).
journalctl --all --output=short-iso --since=-7d --follow |\
  grep --line-buffered -Eiv " 404 " |\
  grep --line-buffered "apache-access" |\
  stdbuf -i0 -o0 -e0 tr -s ' ' |\
  stdbuf -i0 -o0 -e0 cut -d' ' -f8- -


Read stderr of a backgrounded and disowned process with process ID pid.

$ strace -p "$pid" -e trace=write


Open a shell as root.

alice@host: sudo su -
root@host: whoami

Open a bash shell as another user, e.g. www-data.

alice@host: whoami
alice@host: sudo su - www-data -s /bin/bash
[sudo] password for alice:
www-data@host: whoami


A script by Christopher Lovejoy (used with checkdir). Source at GitHub.

Create checksum of files in working directory recursively, excluding files with names: ending in .asc or .ots and files starting with .SUM. Resulting file has pattern: .SUM${digest_name} (e.g. .SUMB2--20230128T013153+0000).

$ sumdir -a sha256 -r -x "*.asc" -x "*.ots" -x ".SUM*"
$ sumdir -a b2 -r -x "*.asc" -x "*.ots" -x ".SUM*"


See File compression notes.

Extract a compressed archive (e.g. .tar.xz) in the current working directory.

$ tar -xf archive.tar.xz
Extract to a different directory some/path/. (The positioning of -C is important.)
$ tar -xf archive.tar.xz -C some/path/


Echo stdout to stderr (ref):

$ echo "This is standard error" | tee /dev/stderr | sed 's/error/out/g'
This is standard error
This is standard out


View process, sorted by CPU usage

$ top


  • Arrow keys & page up/down: Navigate through the displayed list in the Task area.
  • q: Finish the top with the q-key.
  • S-p: Sort the processes by CPU usage.
  • S-m: Sort the processes by memory (%MEM) usage.
  • S-t: Sort the processes by running-time.
  • S-n>: Sort the processes by process ID.
  • t: Changes the display of the CPU usage in the summary section.
  • m: Changes the display of memory usage in the summary section.
  • S-r: Sort the processes in ascending order instead of descending (default).
  • c: By pressing c, the 'Command' column shows the entire path from which the processes were started.
  • S-v: Shows the parent / child process hierarchy.
  • k: Prompts for a process ID and closes the specified process. By default, SIGTERM is used for a graceful shutdown of the process. For a forced shutdown, you use SIGKILL.


Remove unwanted character sets

Keep only printable characters and spaces from a string.

name="message:おはよう ございます.";
name_new="$( printf "%s" "$name" | tr -dc '[:graph:][:space:]' )";
printf "%s\n" "$name";
printf "%s\n" "$name_new";
This results in:
message:おはよう ございます.


Unzip to directory foo

$ mkdir foo
$ unzip -d foo

Unzip archives containing file names encoded in the Shift JIS Japanese encoding.[35]

$ unzip -O shift-jis


Mount a volume.

$ veracrypt volume.hc

Unmount all volumes.

$ veracrypt -d
If you get an error message resembling Error: umount: /media/veracrypt1: target is busy, then identify the offending process with lsof[36]:
$ lsof | grep '/media/veracrypt1'

Unmount a specific volume.

$ veracrypt -d volume.hc

Create a volume.

$ veracrypt -t -c


Limit bandwidth of network interface eth0[37] to 5000kbps download and 1000kbps upload.

$ wondershaper eth0 5000 1000

Clear wondershaper limits.

$ wondershaper clear


Download lowest quality.[38]

$ yt-dlp -S '+size,+br'

Write automatic subtitles of a YouTube video to a .vtt file:

$ yt-dlp --write-subs --write-auto-subs
Parse such a .vtt file in order to extract the text (reading every 8th line with an offset)
clear; offset=1; cycle=8; n=0; {
  while read -r line; do
    if [[ ! $((n % cycle)) -eq "$offset" ]]; then
      ((n++)); continue; fi;
    printf "%s\n" "$line";
  done < Unicode\ and\ Byte\ Order\ \[bbkUn0o3L1Y\].en.vtt;
  echo "STATUS:Done." 1>&2;
} | grep -v "^$";


Convert several lines of stdin into words. This may be useful if a command needs to perform an operation on all items in a long newline-delimited list as argument parameters instead of standard input. The following expressions are equivalent calls of ls to list the files foo, bar, and baz:

$ printf "foo\nbar\nbaz\n" | xargs -d '\n' ls -alh;
$ ls -alh foo bar baz;
Note: -d '\n' requires that only newlines are used to separate (i.e. delimit) arguments. The -d option is necessary in newline-delimited lists because xargs will split lines on whitespace characters such as the space character. For example, printf "1 qux\n2 quux\n3 corge\n" | xargs -d '\n' ls -alh; will not apply ls -alh to the three files 1 qux, 2 quux, and 3 corge, but instead will erroneously use six other files 1, qux, 2, quux, 3, and corge.


Baltakatei history

See also

External links


  2. Corrado Topi. (2018-11-26). “How to list dependent packages (reverse dependencies)?”. Accessed 2023-07-04.
  4. Baltakatei: 2024-01-12: Note, md5 may be replaced with sha256 to get a SHA-256 digest.
  5. alex (2010-11-01). “How can I get a base64 encoded shaX on the cli?”. Accessed 2024-01-11.
  6. See .
  7. Mendel Cooper. (2014-03-10). “Advanced Bash-Scripting Guide: 10. Manipulating Strings”. Accessed 2024-02-12.
  8. u1686_grawity. (2012-09-06). “How do I create a 1GB random file in Linux?”. Accessed 2023-07-01.
  9. Gite, Vivek. (2023-03-11). “How To Find My Public IP Address From Linux CLI”. Accessed 2023-05-08.
  10. FFmpeg and VP9 Encoding Guide”. (2024-01). Accessed 2024-05-23.
  11. BashFAQ/089 I'm reading a file line by line and running ssh or ffmpeg, only the first line gets processed!”. (2022-10-30). Accessed 2023-07-29. Archived from the original on 2023-07-23.
  12. roaima. (2022-09-22). “Bash variable truncated when passed into ffmpeg”. Accessed 2023-07-29. Archived from the original on 2023-07-29.
  13. Baltakatei: 2024-03-01: See ffmpegʼs map option. Order is important.
  14. louise. (2011-06-04). “How to extract duration time from ffmpeg output?”. Accessed 2024-02-10.
  15. Nemo. (2019-04-25). “Using ffmpeg to split an Audible audio-book into chapters?”. Accessed 2024-01-20.
  16. Celada. (2014-10-24). “Why does BASH process substitution not work with some commands?”. Accessed 2023-07-14.
  17. 17.0 17.1 git-branch - List, create, or delete branches”. (2019-08-16). Accessed 2023-04-20.
  18. VonC. (2017-05-17). “How do I disable git's credential helper for a single repository?”. Stack Overflow. Accessed 2023-08-02. Archived from the original on 2023-08-02.
  19. Kurt Pfeifle. (2016-06-16). “[1]”. Accessed 2023-10-28.
  20. 20.0 20.1 Narad Shrestha. (2023-07-14). “How to Use ‘lsof’ Command to Check Open Files in Linux”. Accessed 2024-01-05.
  21. John Kerl (1997-04-28). “How to use the Unix command-line mail tool”. Accessed 2024-01-05.
  22. timaschew. (2012-11-17). “How do I purge a linux mail box with huge number of emails? [closed]”. Stack Overflow. Accessed 2023-06-06.
  23. Stephen Kitt. (2021-07-01). “Why does make only accept tab-indentation?Stack Exchange. Accessed 2023-07-10. Archived from the original on 2023-05-28.
  24. cnicutar. (2011-05-10). “Makefile to compile multiple C programs?”. Stack Overflow. Accessed 2023-07-13. Archived from the original on 2023-07-14.
  25. 25.0 25.1 Gilles. (2012-01-08). “How to check 'mdadm' RAIDs while running?”. Accessed 2023-03-26. Archived from the original on 2015-09-25.
  26. applicative. (2010-09-26). “Are there any tools to convert markdown to Wiki text in other formats”. Accessed 2024-02-27.
  27. Baltakatei: 2023-09-09: Tested with GNU Coreutils 8.32
  28. user79742. (2015-11-01). “Weird float rounding behavior with printf”. Accessed 2023-10-04. Archived from the original on 2023-10-04.
  29. jan. (2014-11-21). “Preserve directory tree while copying with rsync”. Accessed 2024-04-01.
  30. Baltakatei; 2024-01-29: See
  31. Baltakatei; 2024-01-29: See
  32. Anthony Geoghegan. (2016-05-09). “Get SSH server key fingerprint”. Accessed 2023-06-25.
  33. a3nm. (2011-06-19). “Turn off buffering in pipe”. Stack Exchange. Accessed 2023-06-06.
  34. Using the top command in Linux”. (n.d.). Accessed 2024-01-06. Archived from the original on 2023-11-27.
  35. Nicolas Raoul. (2017-07-11). “How to unzip a Japanese ZIP file, and avoid mojibake/garbled characters”. Accessed 2024-04-12.
  36. Tudor, Frank. (2011-10-24). “How to unmount a busy device [closed]”. Accessed 2023-07-25. Archived from the original on 2023-06-20.
  37. Baltakatei: 2024-01-12: Network interfaces and DHCP-assigned IP addresses can be listed via ifconfig.
  38. Sherman. (2021-08-06). “Download the lowest quality video with youtube-dl”. Accessed 2024-02-10.


  1. Baltakatei: See BK-2020-03:user/