Terminal Takeaway πŸ₯‘

Can I just put out here that I ABSOLUTELY LOVE THIS THREAD!!!

Thank you so much for this compilation of delightful tips and tricks. Every time I stop in here, I learn something fun, helpful, or revolutionary.

Thank you!

3 Likes

ARG!! Where do I put my executable???

Asking your distro’s opinion… $PATH contains a : deliminated string of each directory that’s checked for executables and the directory names reveal if they’re managed and who they’re intended for.

Keep in mind every distro/system can be different though the terminology is often shared, this example is for Fedora:

# Try it:

$ echo $PATH
/home/ulfnic/.local/bin:/home/ulfnic/bin:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin

# Easier to read:
$ echo $PATH | tr ':' '\n'
# Or
$ echo $PATH | sed 's/:/\n/g'
/home/ulfnic/.local/bin
/home/ulfnic/bin
/usr/local/bin
/usr/bin
/usr/local/sbin
/usr/sbin

If I attempt to run xcalc (the calculator 99.99% of Linux users are surprised to learn they have installed), the system will check the current directory, then those 6 directories from top to bottom till it finds xcalc and runs it.

Where is xcalc?

$ which xcalc
/usr/bin/xcalc

Should I uninstall xcalc?
That’s a philiosophical question beyond the scope of this guide.

Terminology

Everyone describes these directories a bit differently but this is my practical summary:

  • local is for files that aren’t ordinarily managed by the system (with things like dnf or apt). It’s a safe place for files to not be overwritten during standard installations and updates.

    It’s commonly refered to as the place for β€œlocal” or β€œunique” files but syncing them against a public/private repo is just as valid a use case.

  • bin is short for binary but all executables are welcome.

  • sbin is like bin but intended for the superuser only.

  • usr is for all users.

  • home is for specific users.

Breaking it down

/home/ulfnic/.local/bin ← I’m a custom executable intended for Ulfnic
/home/ulfnic/bin ← I’m a managed executable intended for Ulfnic
/usr/local/bin ← I’m a custom executable intended for everyone
/usr/bin ← I’m a managed executable intended for everyone
/usr/local/sbin ← I’m a custom executable intended for the superuser
/usr/sbin ← I’m a managed executable intended for the superuser

File & folder permissions ultimately determine who has access to what, for example if I chmod +x instead of chmod u+x a file in my user folder, all users will be able to execute it but the above is a decent guide to what these folders are generally intended for.

Where should I put my executable?

For a specific user: /home/$USER/.local/bin
For all users: /usr/local/bin
For superuser: /usr/local/sbin

BONUS: Making a shim

Because /local/bin directories are checked prior to their /bin equivalents it makes it easy to run a script first that then runs the program being asked for.

Example:

$ which nano # Make sure you know where the nano binary is first.
/usr/bin/nano

$ sudo touch /usr/local/bin/nano # Make a file named nano in /usr/local/bin/ so it's found first and run instead of the real nano.

$ sudo nano /usr/local/bin/nano # Edit
# Paste the following:
#!/usr/bin/env sh
echo "vim empowers users by teaching them lots of useful key"
echo "commands found in other terminal applications!"
echo ""
read -r -p "Are you sure you only want to learn nano? [y/N] " Res
case "$Res" in
	[yY][eE][sS]|[yY])
		# Respect the user's decision, Linux is about choice.
		# Make sure to use nano's direct path gathered from `which nano` or this script will loop.
		# Appending "$@" includes all the arguments so `nano myfile.txt` will still work.
		/usr/bin/nano "$@"
	;;
	*)
		# Check if vim is installed.
		if $( -z which vim 2>/dev/null); then
			echo
			echo "Your distro is afraid even the GPL won't protect"
			echo "them from the liability of users getting stuck in VIM!"
			echo "You need to install it at your own risk."
		else
			echo
			echo "Godspeed."
			sleep 1
			echo "Wait! Esc :q!"
			sleep 1
			vim "$@" # Transcend the user.
		fi
	;;
esac
# Save & exit (Ctrl + x)
$ sudo chmod +x /usr/local/bin/nano # Make it executable to all users

# The terminal session may need to be refreshed to see the change
$ exec bash

# Test the shim
$ nano

# Remove the shim in compliance with HR
$ sudo rm /usr/local/bin/nano
5 Likes

HAHAHAAAA!!! Nice! :rofl:

1 Like

Some examples of PCRE RegEx with inline Perl:

#!/usr/bin/env sh

# Define values for examples
$ REGEX="23"
$ VAL="1234"
$ ADD_VAL="+"

# Insert ADD_VAL before the RegEx match
$ perl -e "'$VAL' =~ m/$REGEX/s; print \"$\`$ADD_VAL$&$'\";"
1+234

# Insert ADD_VAL after the RegEx match
$ perl -e "'$VAL' =~ m/$REGEX/s; print \"$\`$&$ADD_VAL$'\";"
123+4

# Replace the RegEx match with ADD_VAL
$ perl -e "'$VAL' =~ m/$REGEX/s; print \"$\`$ADD_VAL$'\";"
1+4

# Remove RegEx match from VAL
$ perl -e "'$VAL' =~ m/$REGEX/s; print \"$\`$'\";"
14

# Output RegEx match within VAL
$ perl -e "'$VAL' =~ m/$REGEX/s; print \"$&\";"
23

1 Like

The Linux Foundation: Filesystem Hierarchy Standard

The definitive guide to, β€œWhere the hell do I put this?” and, β€œWhy the hell is this put here?”

Filesystem Hierarchy Standard

2 Likes

Simple password based AES-256 symmetric encryption using gpg:

Try it:

# Make a file
echo 'pkgs.org is a distro search engine for packages!' > 1-toencrypt.txt
# Encrypt
gpg -cao 2-encrypted.txt --cipher-algo AES256 --no-symkey-cache 1-toencrypt.txt
# Decrypt
gpg -o 3-unencrypted.txt --no-symkey-cache 2-encrypted.txt

Result:

β”œβ”€ 1-toencrypt.txt
β”œβ”€ 2-encrypted.txt
└─ 3-unencrypted.txt

Break down:

# Make a file containing a secret
echo 'pkgs.org is a distro search engine for packages!' > toencrypt.txt

# Encrypt toencrypt.txt using AES256
gpg -cao encrypted.txt --cipher-algo AES256 --no-symkey-cache toencrypt.txt
	# -c | --symmetric, Encrypt with a symmetric cipher using a passphrase.
	# -a | --armor, use ASCII "armored" output instead of binary (useful for Email, Web POST, ect)
	# -o | --output <file>, output file (default: input file name with ".asc" appended)
	# --cipher-algo <algorithm>, which algorithm to use (default: AES128)
		# Bonus: See which algorithms `gpg` supports by using `gpg --version`
	# --no-symkey-cache, disable gpg's default behavior of caching passwords

# Enter password at prompts

# Output encrypted file
cat encrypted.txt

-----BEGIN PGP MESSAGE-----

jA0ECQMCBXVoK9eD6ar/0nYBBz0B2EX0Z7R6UaOjjwDUNl3TublbeCy7rlJ7j6+t
Nqmvbm1wgmqsY/eY8171wMDInaa1M/VAoRFSIDRTAkx798ymbbsx/CUJakRH3Kll
kpWG1UfyDqUgWACOgpQxvjZyA4qhlruvYuI7IXeb0KEskFUEMdeQ
=33Fs
-----END PGP MESSAGE-----

# Unencrypt
gpg -o unencrypted.txt --no-symkey-cache encrypted.txt
	# -o | --output <file>
	# --no-symkey-cache, disable gpg's default behavior of caching passwords

# Enter password at prompt

# Output unencrypted file
cat unencrypted.txt

pkgs.org is a distro search engine for packages!

Bonus: Clearing gpg-agent password cache

Without the --no-symkey-cache argument above, passwords are cached by the gpg-agent allowing decryption of those files without a password until the user logs out.

The password manager pass also has gpg-agent cache the master password in the same way so this might be useful to pass users too.

To remove all cached passwords without having to logout, use the following command:

gpgconf --reload gpg-agent
2 Likes

Why the name change?

  1. There seems to already be various other Terminal Tuesdays which came first so this is squeezing in on other people’s namespace.
  2. There’s a hidden β€œrule 0” joke that I made this on a Monday and almost never posted on Tuesday but it was a bit too stealthy and is more likely to create confusion.
  3. It’d be nice to have a domain that isn’t taken for the thread :slight_smile:

Without further ado! Welcome to Terminal Takeaway :takeout_box:

2 Likes

It makes more sense and I think I never really posted something on Tuesday either. :slight_smile: Every day should be a terminal day.

β€œArrays” in POSIX

POSIX Shell doesn’t have arrays but it does have β€œan array”… kind of. :stuck_out_tongue:

You can use the tools for managing arguments in semi-familiar ways to how arrays are managed in BASH. Each function has it’s own arguments too so each one has it’s own β€œarray”.

Play in terminal:

# Set arguments (do this first if playing in terminal)
set Setting 5 new array "elements here"

# Append an argument
set -- "$@" "and 1 more"

# Print number of arguments
echo $#

# Print all arguments (argument spaces and separator spaces are separate)
echo $@

# Print all arguments (spaces are ambiguous)
echo $*

# Print the 2nd argument
# Note: After $9 braces should be used to assure cross shell compatibility, ie: ${10}
echo $2

# Remove 2 arguments from the beginning
shift 2

# Remove 2 arguments from the end using rev
set -- $(rev <<< "$@")
shift 2
set -- $(rev <<< "$@")

# Remove 2 arguments from the end cycling through a loop
for i in $(seq 1 $#); do
	[ "$i" -le $(($# - 2)) ] && set -- "$@" "$1"
	shift
done

# Remove all arguements
shift $#

# Loop through all arguments
for Arg do
	echo "$Arg"
done

Running an app as a different user in the same X session:

# Create a test user account for the example and give it a password
sudo useradd testdummy
sudo passwd testdummy

# Option 1. Using su (Switch User)
su - testdummy -c "DISPLAY=:0 /usr/bin/firefox"

# Option 2. Using runuser
sudo runuser -u "testdummy" -- /usr/bin/firefox

# Cleanup: Remove the test account and it's home directory
sudo userdel -r testdummy

Useful for running apps in different configurations if they don’t support profiles (which Firefox does) and sending notify-send alerts from scripts run with sudo, ex:

runuser -u "ulfnic" -- notify-send "Backup complete!" -t 0

β€œThe difference between the commands runuser and su is that runuser does not ask for a password (because it may be executed by the root user only) and it uses a different PAM configuration. The command runuser does not have to be installed with set-user-ID permissions.”

https://www.linux.org/docs/man1/runuser.html

1 Like

Controlling Keyboard LEDs

Try it:

xset led named "Scroll Lock"
xset -led named "Scroll Lock"

Behavior:

  • xset won’t cause the system to forget or mismatch the organic state of the LED. Turning an LED β€œoff” with xset just returns it to it’s organic state so if it was originally on before turning it β€œon” then it’ll stay on.
  • xset doesn’t activate the mode the LED is associated with. *

Going beyond Scroll Lock:

So what about the other LEDs?? This command will turn them all on…

# 1. Turn on the Christmas Tree!
xset led on

# 2. Express disappointment

# 3. Check if it did anything
xset q
Keyboard Control:
  auto repeat:  on    key click percent:  0    LED mask:  ffffe7fc
  XKB indicators:
    00: Caps Lock:   off    01: Num Lock:    off    02: Scroll Lock: on 
    03: Compose:     on     04: Kana:        on     05: Sleep:       on 
    06: Suspend:     on     07: Mute:        on     08: Misc:        on 
    09: Mail:        on     10: Charging:    on     11: Shift Lock:  off
    12: Group 2:     off    13: Mouse Keys:  on 
# 4. Switch LEDs off
xset led off

* It turns out most distros consider Caps Lock and Num Lock LEDs forbidden fruit and for good reason. Below is a guide to allow you to use them but (at least on my machine) they reliably produce unpredictable keyboard results such as the Enter key being held down, Shift being held down, being totally locked out of the numlock keys and sometimes all of these behaviors stick around even after the LEDs are turned off.

Scroll lock appears to be the only β€œsafe” LED compared to the fore-mentioned. Caps Lock is usually ok and Num Lock opens the door to the chaos dimension.

# Enabling Caps Lock and Num Lock LEDs (caution, see above ^)
# Guide applies to: Debian, Ubuntu, Fedora and CentOS

# === Option 1. Manually adjust: ===
# Caps Lock:
sudo nano /usr/share/X11/xkb/compat/ledcaps
# Change: !allowExplicit; to allowExplicit;

# Num Lock:
sudo nano /usr/share/X11/xkb/compat/lednum
# Change: !allowExplicit; to allowExplicit;

# === Option 2. Auto-adjust: ===
# Caps Lock:
sudo sed -i 's|\!allowExplicit|allowExplicit|g' /usr/share/X11/xkb/compat/ledcaps

# Num Lock:
sudo sed -i 's|\!allowExplicit|allowExplicit|g' /usr/share/X11/xkb/compat/lednum

# Logout and back in

# Test
xset led named "Caps Lock"
xset -led named "Caps Lock"
xset led named "Num Lock"
xset -led named "Num Lock"

Scroll Lock LED alarm script:

cd /usr/local/bin
sudo touch ./sl-alarm
sudo chmod 755 ./sl-alarm
sudo nano ./sl-alarm
# Paste the following:
#!/usr/bin/env sh

# If the application is terminated, set Scroll Lock LED off
trap 'xset -led named "Scroll Lock"' EXIT

while true; do
	xset led named "Scroll Lock"
	sleep 0.4
	xset -led named "Scroll Lock"
	sleep 0.4
done
# Save & quit
# Run
sl-alarm
# Ctrl + c to quit

Extra:

You can also activate LEDs using their id from xset q + 1

# Example:
xset led 1 # Caps Lock
xset led 2 # Num Lock
xset led 3 # Scroll Lock
2 Likes

Does anyone know of a way to send keystrokes to an X window? Other than…

xdotool type "something"
xdotool key "a"
xvkbd -text "something"

List:

xdotool
xvkbd
crikey [website] - thanks to Ethanol

This may not be exactly what you’re looking for but…

I know a program called β€œcrikey”

https://shallowsky.com/software/crikey/

It’s used for outputting a string with a hotkey wherever the cursor is. You can pipe stuff into it as well.
Example:
echo "hello" | crikey -i -s 2

This will print β€œhello” after two seconds to the active window. I use this with zbarcam to get raw barcode data from a webcam and type it into a database form input.

Example:
zbarcam /dev/video0 --raw | crikey -i

1 Like

That’s a good tool to know about.

Ironically one of the things that makes it so cool (handling of special codes) makes it not work for my project although getting more options was sort of a quest for a silver bullet anyway and that’s quickly been turning into the realization I need to do a lot of custom handling to make this work.

I’ve been putting off the description because It’s solvable with a single line of code unless I start describing the 1,000 edge cases :P. I’ll post it soon.

Only 28 lines to start an X Session from TTY

sx is a replacement for startx and xinit which i’m currently using to start XFCE.

sx is a tiny fraction of the size of startx and xinit showing what cutting a few features and edge cases can do for making code easy to read and hack on.

Compare https://github.com/Earnestly/sx -to- https://github.com/freedesktop/xorg-xinit

Installation:

# Set up the init script for sx

mkdir -p ~/.config/sx/
touch ~/.config/sx/sxrc

# sx requires this be executable
chmod 700 ~/.config/sx/sxrc
vim ~/.config/sx/sxrc

# Paste what would normally be in your ~/.xinitrc file

# For example, I need my dunst notifier started along with
# startxfce4 so my ~/.config/sx/sxrc looks like this:

dunst &
startxfce4

# Download script and install to /usr/local/bin/
sudo sh -c "wget -q -O - https://raw.githubusercontent.com/Earnestly/sx/master/sx > /usr/local/bin/sx"

# Confirm against original
cat /usr/local/bin/sx

sudo chmod 755 /usr/local/bin/sx

# sx is now ready! Enter a TTY and launch an X Session using:
sx

Note: I boot to a TTY but If you’re using a Desktop Manager like LightDM you’ll need to configure it to use sx. Alternatively you can switch to a TTY and start an additional X Session using sx as it uses the TTY you’re in not TTY7.

1 Like

Weather report in terminal

# Try it
wget -qO- "https://wttr.in/"
     \  /       Partly cloudy
   _ /"".-.     +22(25) Β°C     
     \_(   ).   ↙ 19 km/h      
     /(___(__)  10 km          
                0.0 mm         
                                                       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                                                       
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€  Sat 17 Jul β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚            Morning           β”‚             Noon      β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜     Evening           β”‚             Night            β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚               Mist           β”‚  _`/"".-.     Light rain sho…│    \  /       Partly cloudy  β”‚    \  /       Partly cloudy  β”‚
β”‚  _ - _ - _ -  18 Β°C          β”‚   ,\_(   ).   20 Β°C          β”‚  _ /"".-.     21 Β°C          β”‚  _ /"".-.     18 Β°C          β”‚
β”‚   _ - _ - _   ↙ 14-17 km/h   β”‚    /(___(__)  ↙ 22-25 km/h   β”‚    \_(   ).   ↓ 22-25 km/h   β”‚    \_(   ).   ↓ 20-28 km/h   β”‚
β”‚  _ - _ - _ -  7 km           β”‚      β€˜ β€˜ β€˜ β€˜  10 km          β”‚    /(___(__)  10 km          β”‚    /(___(__)  10 km          β”‚
β”‚               0.1 mm | 66%   β”‚     β€˜ β€˜ β€˜ β€˜   0.1 mm | 33%   β”‚               0.0 mm | 0%    β”‚               0.0 mm | 0%    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                                       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                                                       
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€  Sun 18 Jul β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚            Morning           β”‚             Noon      β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜     Evening           β”‚             Night            β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚               Cloudy         β”‚  _`/"".-.     Patchy rain po…│    \  /       Partly cloudy  β”‚    \  /       Partly cloudy  β”‚
β”‚      .--.     20 Β°C          β”‚   ,\_(   ).   +23(24) Β°C     β”‚  _ /"".-.     22 Β°C          β”‚  _ /"".-.     19 Β°C          β”‚
β”‚   .-(    ).   ↙ 20-23 km/h   β”‚    /(___(__)  ↓ 22-26 km/h   β”‚    \_(   ).   ↓ 23-33 km/h   β”‚    \_(   ).   ↓ 23-37 km/h   β”‚
β”‚  (___.__)__)  10 km          β”‚      β€˜ β€˜ β€˜ β€˜  10 km          β”‚    /(___(__)  10 km          β”‚    /(___(__)  10 km          β”‚
β”‚               0.1 mm | 61%   β”‚     β€˜ β€˜ β€˜ β€˜   0.0 mm | 30%   β”‚               0.0 mm | 0%    β”‚               0.0 mm | 0%    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                                       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                                                       
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€  Mon 19 Jul β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚            Morning           β”‚             Noon      β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜     Evening           β”‚             Night            β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚    \  /       Partly cloudy  β”‚    \  /       Partly cloudy  β”‚    \  /       Partly cloudy  β”‚    \  /       Partly cloudy  β”‚
β”‚  _ /"".-.     20 Β°C          β”‚  _ /"".-.     +23(24) Β°C     β”‚  _ /"".-.     22 Β°C          β”‚  _ /"".-.     19 Β°C          β”‚
β”‚    \_(   ).   ↙ 14-16 km/h   β”‚    \_(   ).   ↙ 16-18 km/h   β”‚    \_(   ).   ↓ 13-21 km/h   β”‚    \_(   ).   ↓ 7-14 km/h    β”‚
β”‚    /(___(__)  10 km          β”‚    /(___(__)  10 km          β”‚    /(___(__)  10 km          β”‚    /(___(__)  10 km          β”‚
β”‚               0.0 mm | 0%    β”‚               0.0 mm | 0%    β”‚               0.0 mm | 0%    β”‚               0.0 mm | 0%    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Moon phase in terminal

# Try it
wget -qO- "https://wttr.in/moon"
                       -------.	 
                         . .   `--.	 
                         .       . `-.	 
                        .  @@@@@      `-.	 
                      @   @@@@@@@   .    \	 
                      @   @@@@@@@       . \.	 
                      @.   @@@@@@@   O      \	 
                          @@@@@@@@@@     @@@ \	 
                       . @@@@@@@@@@@@@ o @@@@|	 
                          @@@@@@@@@@@@    @@  \	 First Quarter +
                       o     @@@@@@@@ @@@@    |	 0 10:02:27
                           .  @@   . @@@@@@@  |	 Full Moon -
                       .-.     @@@   @@@@@@@  |	 6  6:23:22
                       `-'   . @@@@   @@@@  o /	 
                                @@   .       |	 
                      /  .  O    .     o   . /	 
                               .    .       /	 
                      __   .      .   .-. /'	 
                                     `-' /	 
                         o    O   .   .-'	 
                              .    .-'	 
                        .      .--'	 
                       -------'	 

Some highlights:

#!/bin/sh
# ^-- So the forum colorizes this correctly

# Output a basic usage guide (check the Git for full instructions):
wget -qO- "https://wttr.in/:help"

# Weather is by IP location by default. Select a city as follows:
wget -qO- "https://wttr.in/berlin"

# You can also add URL parameters, this one selects the German language using "lang=de":
wget -qO- "https://wttr.in/berlin?lang=de"

# Get the report in JSON using "format=j1":
wget -qO- "https://wttr.in/berlin?lang=de&format=j1"

# Data rich output using "format=v2"
wget -qO- "https://wttr.in?format=v2"

Alternatively you can use curl

wget
	-q		# Quiet
	-O -	# Output to terminal
	-qO-	# ^ these combined

wttr.in is a Web API wrapper for delivering output from the included wego project. Check out the projects below:

wttr.in (wego as a web service)

wego

4 Likes

I set up with a systemd user service with a shell script using wttr.in, to populate the weather in swaybar originally. wttr.in is pretty neat.

Description="Pull weather using wttr.in for sway bar" 

[Service]
Type=simple
ExecStart=%h/bin/weathercache.bash

[Install]
WantedBy=sway-session.target  
Description=Pull from wttr.in every 30 minutes

[Timer]
Persistent=true
OnBootSec=30
OnCalendar=*:0/30
Unit=weathercache.service

[Install]
WantedBy=timers.target
#!/bin/bash
LOCATION="zipcode"
FORMAT="2"
/usr/bin/curl https://wttr.in/${LOCATION}?format="${FORMAT}&u" > ~/.cache/weather.cache
1 Like

I love this thread!

3 Likes

Resizing your GUI terminal emulator on demand

Note: This guide is for xfce4-terminal, mate-terminal and gnome-terminal though it may work on others. It doesn’t work in konsole (info) or alacritty, these will likely need something like a wmctrl or xdotool solution.

Instructions at the bottom for how to make this work in xterm.

# Try it

# Check terminal size
stty size

# Resize terminal to 30 rows x 125 columns using a native escape sequence
printf '\033[8;30;125t'

# Check just the rows
stty size | cut -d ' ' -f 1
# Check just the columns
stty size | cut -d ' ' -f 2

Sometimes wrapped text can lead to undesirable outcomes, using wget -qO- "https://wttr.in/" for example needs 125 columns to prevent wrapping.

w

A quick n’ dirty solution to set 125 columns without adjusting the rows would be:

printf '\033[8;%d;125t' "$(stty size | cut -d ' ' -f 1)"
wget -qO- "https://wttr.in/"

…though a more elegant solution would only change the rows if they were too small and be easier to read:

nano ~/.bashrc
# Add the following to the bottom:
# Show me the weather
function weather (){
	# If the terminal has less than 125 columns, increase the columns to 125
	CurCols=$(stty size | cut -d ' ' -f 2)
	if [ "$CurCols" -lt "125" ]; then
		NewCols=125
		NewRows=$(stty size | cut -d ' ' -f 1)
		printf '\033[8;%d;%dt' "$NewRows" "$NewCols"
	fi
	wget -qO- "https://wttr.in/"
}
# Save & quit
# Open a new terminal
weather

Making this work in XTerm

XTerm needs allowWindowOps set to true for this to work. At startup your distro will run something similar too xrdb < ~/.Xresources, xrdb < ~/.Xdefaults or neither. If it’s neither one of these need to be added to startup.

For this example i’m using ~/.Xresources

nano ~/.Xresources
# Add the following to the bottom:
xterm*allowWindowOps: true
# Save & quit

# Load the configuration
xrdb < ~/.Xresources

# Open a new xterm window
# Test
printf '\033[8;20;40t'
2 Likes

Extra: Universal GUI terminal resizing script

Intended for xfce4-terminal, mate-terminal, gnome-terminal (see: above)

sudo touch /usr/local/bin/termsizeto
sudo chmod 755 /usr/local/bin/termsizeto
sudo nano /usr/local/bin/termsizeto

# Paste the following:
#!/usr/bin/env sh

# Examples of use:
# termsizeto 70 20			# Set terminal size to 70 columns, 20 rows
# termsizeto 70 auto		# Set terminal size to 70 columns, existing rows
# termsizeto 70 20 min		# Set terminal minimum size to 70 columns, 20 rows
# termsizeto 70 20 max		# Set terminal maximum size to 70 columns, 20 rows

# Get requested terminal size
NewCols=$1
NewRows=$2

# Get current terminal size
CurCols=$(stty size | cut -d ' ' -f 2)
CurRows=$(stty size | cut -d ' ' -f 1)

# Normalize blank and "auto" sizes to the current terminal size
[ -z "$NewCols" -o "$NewCols" = "auto" ] && NewCols=$CurCols
[ -z "$NewRows" -o "$NewRows" = "auto" ] && NewRows=$CurRows

# If a terminal size is within min/max tolerances, set the requested
# size to the current terminal size so it doesn't change
if [ "$3" = "min" ]; then
	[ "$NewCols" -lt "$CurCols" ] && NewCols=$CurCols
	[ "$NewRows" -lt "$CurRows" ] && NewRows=$CurRows
elif [ "$3" = "max" ]; then
	[ "$NewCols" -gt "$CurCols" ] && NewCols=$CurCols
	[ "$NewRows" -gt "$CurRows" ] && NewRows=$CurRows
fi

# If the requested terminal size is different, change the terminal's size
[ "$CurCols" -ne "$NewCols" -o "$CurRows" -ne "$NewRows" ] && printf '\033[8;%d;%dt' "$NewRows" "$NewCols"

# Save & quit
# Test
termsizeto 70 20

Example aliases for https://wttr.in/

nano ~/.bashrc

# Add to the bottom:
alias weather='wget -qO- "https://wttr.in/" && [ -x "$(command -v "termsizeto")" ] && termsizeto 125 40 min'
alias moon='wget -qO- "https://wttr.in/moon" && [ -x "$(command -v "termsizeto")" ] && termsizeto 70 27 min'
# Save & quit
# Test
# Open a new terminal and make it's size very small
moon
weather

demo

1 Like