True and some people may have not noticed you can do multiple votes.
Itβs good information though, iβd prefer to do posts people would like most.
True and some people may have not noticed you can do multiple votes.
Itβs good information though, iβd prefer to do posts people would like most.
Thereβs infrequent occasions I canβt paste something but really need to. Usually itβs when iβm using Spice to perform a new OS install or iβm looking at a TTY. Thereβs also times I have to use specific remote viewers for work that donβt have clipboard support.
Auto-typing the contents of the clipboard is deceptively difficult. It can be done in a one-liner but the outcome is best summarized as spray and pray.
xdotool
will turn accidental presses of ctrl, shift and alt into shortcut commands (see: fireworks). This is especially problematic if youβre launching the one-liner with a shortcut combo as itβll react to these keys the moment it starts.All thatβs fixed, introducingβ¦
( pronounced like an ancient Roman name )
#!/bin/env sh
# To do: <FOSS License here>
# Examples of usage:
# cliptokeys
# cliptokeys 0.5 # 0.5 seconds between keystrokes
# Dependencies:
# xdotool, xinput and (xsel or xclip)
# Installation:
# mkdir -p ~/.local/bin/
# mv ./cliptokeys ~/.local/bin/
# chmod u+x ~/.local/bin/cliptokeys
TypeWaitSec=$1;
[ -z "$TypeWaitSec" ] && TypeWaitSec='0.05'
# Check for missing package(s)
if ! which xinput 2> /dev/null; then
echo "Missing package: xinput"
exit
elif ! which xdotool 2> /dev/null; then
echo "Missing package: xdotool"
exit
fi
FocusedWindowId=$(xdotool getwindowfocus)
# Get clipboard contents
if which xsel 2> /dev/null; then
ClipOut=$(xsel -ob)
elif which xclip 2> /dev/null; then
ClipOut=$(xclip -o -sel c)
else
echo "Missing package: xsel OR xclip"
exit
fi
# Handle keyboard locking
KeyboardIds=$(xinput list | grep keyboard | cut -d '=' -f 2 | cut -f 1)
KeyboardStates() {
for Id in $KeyboardIds; do xinput --$1 $Id; done
}
trap 'KeyboardStates enable' EXIT
KeyboardStates disable
# Read the output of the clipboard one character at a time into xdotool to type
CharCount=0
ClipOutLen=$(wc -c <<< $ClipOut) # Note: Using `expr` doesn't count last newline
while read -rN1 Char; do
(( CharCount++ ))
# If the current window loses focus, exit
[ "$FocusedWindowId" != "$(xdotool getwindowfocus)" ] && exit
if [ "$Char" = $'\n' ]; then
# If the newline isn't the last character type the Enter key. Otherwise ignore.
[ "$CharCount" -ne "$ClipOutLen" ] && xdotool key Return
else
xdotool type "$Char"
fi
sleep $TypeWaitSec
done <<< $ClipOut
Remote viewers often capture keystrokes so local keyboard shorcuts donβt work. You can get around this by clicking on the titlebar of the viewer, hit your chosen shortcut to start the script and it should βtypeβ the text into the focused window inside the viewer. In my case it this works with spice
viewer launched from virt-manager
.
The Digital Ocean browser based console hates pasting long strings, like SSH keys, and drops tons of characters throughout the string. This probably would have saved me the grief.
Similar to edge cases you may need cliptokeys
for, you may also want to get text thatβs stuck in an image or an interface that doesnβt allow select to copy.
# Try it
sudo [apt/dnf] install maim
maim --select --hidecursor --format=png --quality=10 "~/MyScreenshot.png"
xdg-open "~/MyScreenshot.png"
Thereβs A LOT of ways to take a screenshot but I wanted something as script friendly as possible. maim
fit the bill well though a good improvement would be supporting what the user already has in a way thatβs minimally invasive to the script.
# Try it (bad result)
sudo [apt/dnf] install tesseract
tesseract "~/MyScreenshot.png" "~/MyText.txt"
cat ~/MyText.txt
tesseract
is the go-to Linux solution for OCR (itβs been in the TT rules since day 1). From my personal guess it was developed to handle scanned documents way back. The images from which would be very large so if you zoomed to 100% youβd see huge text.
Solving problems: This may be why tesseract
is unusable for reading small text from screenshots. Luckily the problem is fixed by up-sizing images by 400% from a great answer here.
A natural choice for scripting image editting is ImageMagik though I have a feeling thereβs a lot of ways to do this and iβd love to make the script use Krita, GIMP, ect if the user already has them.
# Try it (good result)
sudo apt install imagemagik # Debian, Ubuntu
sudo dnf install ImageMagik # Fedora
mogrify -modulate 100,0 -resize 400% "~/MyScreenshot.png"
tesseract "~/MyScreenshot.png" "~/MyText.txt"
cat ~/MyText.txt
βAll of your namespace is belong to us.β
~ 2050/1/1, ImageMagik upon conquering all of Linux namespace.
Combining the above, I presentβ¦
A project with a terrible name that runs your area selected screenshot through OCR and places the interpreted text in your clipboard.
This project is somewhat accurate but would benefit a lot from better image preparation for OCR such as sharpening edges and contrast.
Problem:
# sed -i 's/ForumCantShowThisCharacter//g' "$TmpFilePathPrefix.txt"
This command is intended to remove instances of an artifact character that keeps showing up for reasons I donβt know but the forum wonβt show it. Just run the program, copy the character into the sed
command and uncomment it.
#!/usr/bin/env sh
# Dependencies:
# ImageMagick, sed, xsel/xclip, tesseract, maim
TmpFilePathPrefix="$HOME/.cache/shottoclip$$"
function CleanUp(){
[ -f "$TmpFilePathPrefix.txt" ] && rm "$TmpFilePathPrefix.txt"
[ -f "$TmpFilePathPrefix.png" ] && rm "$TmpFilePathPrefix.png"
}
trap CleanUp EXIT
# User drags cursor over what they want OCR'ed
maim --select --hidecursor --format=png --quality=10 "$TmpFilePathPrefix.png"
# Resize to 400%
mogrify -modulate 100,0 -resize 400% "$TmpFilePathPrefix.png"
# OCR the image
tesseract "$TmpFilePathPrefix.png" "$TmpFilePathPrefix" &> /dev/null
# Remove an artifact that keeps showing up for some reason
# sed -i 's///g' "$TmpFilePathPrefix.txt"
# Place text in clipboard
if [ $(which xsel 2> /dev/null) ]; then
cat "$TmpFilePathPrefix.txt" | xsel --clipboard
elif [ $(which xclip 2> /dev/null) ]; then
xclip -selection clipboard "$TmpFilePathPrefix.txt"
else
echo "Missing packages: xsel OR xclip"
exit
fi
Putting an area selected screenshot in your clipboard as an image:
#!/usr/bin/env sh
# Dependencies: maim, xclip
TmpPath="$HOME/.cache/ss-to-clip-tmp$.png"
trap '[ -f "$TmpPath" ] && rm "$TmpPath"' EXIT
maim --select --hidecursor --format=png --quality=10 "$TmpPath"
xclip -selection clipboard -t image/png "$TmpPath"
Multi-line commands combined with full length flags go a long way for decipherability at a glance. Example:
# Try it:
df \
--local \
--all \
--human-readable
β¦but they can be taken one step further with comments.
It took a while to figure this out and some asking around but the solution is a comment within a subshell prior to the \
next line indicator.
Below is an rsync
explicitly defining what itβs doing (favoring no alias bundles like --archive
) and the comments come from the man
page.
Performance Note: As creating multiple subshells prior to the command running isnβt performant, this is for situations that arenβt millisecond sensitive (although technically commenting anywhere isnβt performative as shell scripts are an interpreted language).
#!/usr/bin/env sh
rsync \
--update `# skip files that are newer on the receiver `\
--links `# copy symlinks as symlinks `\
--atime-preserve=system `# preserve access times `\
--hard-links `# preserve hard links `\
--executability `# preserve executability `\
--acls `# preserve ACLs (implies --perms) `\
--xattrs `# preserve extended attributes `\
--owner `# preserve owner (super-user only) `\
--group `# preserve group `\
--devices `# preserve device files (super-user only) `\
--specials `# preserve special files `\
--times `# preserve modification times `\
--atimes `# preserve access (use) times `\
--devices `# preserve device files (super-user only) `\
--itemize-changes `# output a change-summary for all updates `\
--delete-during `# receiver deletes during the transfer `\
--force `# force deletion of dirs even if not empty `\
--recursive `# recurse into directories `\
MySourceDir \
MyDestinationDir
Put the current date in your clipboard with a keyboard shortcut using XFCE4.
XFCE4 (maybe others) wonβt run scripts as a shortcut command but can pass them as an argument to something that will. Ex: /usr/bin/sh -c '<command>'
App Menu > Keyboard > Application Shortcuts (tab) > + Add
# Format: YYYY-MM-DD
# Using xsel
/usr/bin/sh -c 'date +%Y-%m-%d | xsel --clipboard'
# Using xclip
/usr/bin/sh -c 'date +%Y-%m-%d | xclip -selection clipboard'
I get so much custom mileage out of XFCE. Folks be like: with this new release of XYZ you can β¦ Meanwhile, Iβve been doing that for 4 years with XFCE.
So far this is the best approach iβve found, would love to hear pipewire
or pulseaudio
solutions.
# Try it
# Listen to an audio test in your default browser
xdg-open 'https://youtu.be/6TWJaFD6R2s?t=6'
# Listen to it in mpv using mono audio
mpv --audio-channels=mono 'https://youtu.be/6TWJaFD6R2s?t=6'
# Example alias for your ~/.bashrc
alias ytv-mpv-mono='mpv --audio-channels=mono '
youtube-dl 'https://youtu.be/6TWJaFD6R2s'
ls # Get the video's filename
ffmpeg -i <VideoFilenameHere> -af "pan=mono|c0=FL" <NewVideoFilenameHere>
Q: I donβt have mpv
or ffmpeg
how do I get them?
# Debian/Ubuntu
sudo apt install mpv
sudo apt install ffmpeg
# Fedora
# Enable the RPM Fusion 'Free' repo, https://docs.fedoraproject.org/en-US/quick-docs/setup_rpmfusion/
sudo dnf install https://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm
sudo dnf install mpv
sudo dnf install ffmpeg
Your refusal to make a Zoom account has finally paid off⦠you too can now have a static image!
Weβre using this beautiful piece of kit: GitHub - umlaeute/v4l2loopback: v4l2-loopback device
sudo [apt/dnf] install v4l-utils v4l2loopback ffmpeg
# Load the v4l2loopback module (this needs to be done every reboot)
sudo modprobe v4l2loopback
# If this doesn't work, see troubleshooting section: https://github.com/umlaeute/v4l2loopback
# Get the path to the v4l2loopback video device named "Dummy"
v4l2-ctl --list-device
# Example output:
Dummy video device (0x0000) (platform:v4l2loopback-000):
/dev/video0
# Stream an image to a v4l2loopback device on /dev/video0 using ffmpeg
ffmpeg -loop 1 -re -i '~/Pictures/MyImage.png' -f v4l2 -vcodec rawvideo -pix_fmt yuv420p /dev/video0
# Test the webcam's output with mpv or vlc
# More options here: https://wiki.archlinux.org/title/Webcam_setup#Applications
mpv av://v4l2:/dev/video0
vlc v4l2://:input-slave=alsa://:v4l-vdev='/dev/video0'
# Create 2 dummy webcams as /dev/video5 and /dev/video6 calling them Cam1 and Cam2
sudo modprobe v4l2loopback video_nr=5,6 card_label=Cam1,Cam2
# See OPTIONS section for more: https://github.com/umlaeute/v4l2loopback
# Stream a video to the dummy webcam
ffmpeg -re -i testsrc.avi -f v4l2 /dev/video0
# Stream your desktop to the dummy webcam
ffmpeg -f x11grab -r 15 -s 1280x720 -i :0.0+0,0 -vcodec rawvideo -pix_fmt yuv420p -threads 0 -f v4l2 /dev/video0
# Record the dummy webcam
ffmpeg -f v4l2 -i /dev/video0 -c copy ~/feed.mkv
Interesting. If I run into something similar I may post a script that keeps it running properly.
Side note for all⦠wttr.in, the project that allows you to wget
the weather in terminal appears to be a Web API for delivering output from the wego
project.
So if you want to run it locally without needing a web server you can install wego. I added it to the post above.
Iβd love a way to remove window decorations (borders) for just one window in XFCE. Thatβs probably the only thing itβs missing from my perspective.
It can be done by switching theme but thatβs pretty clunky and affects all windows. I havenβt seen anything yet thatβd let me do it.
Itβs hard for me to read this without seeing it as a challenge.
If youβre recovering from TTY or just want a TUI to manage your mounts, bashmount
makes life very easy especially with mounting luks partitions.
Itβs packaged for Arch, Fedora and Gentoo but can also be installed with a simple wget
because itβs a self-contained BASH script with no dependencies.
βββββββββββββββββββββββββββββ Internal Media ββββββββββββββββββββββββββββββ
1) sda1: EFI System Par... 600M
2) sda2: - 1G
4) zram0: - 4G
5) luks-5044...: fedora_main 952.3G [/home]
6) nvme0n1p1: EFI System Par... 600M [/boot/efi]
7) nvme0n1p2: - 1G [/boot]
ββββββββββββββββββββββββββββββββ Commands βββββββββββββββββββββββββββββββββ
e: eject i: info m: mount o: open u: unmount
[Enter]: refresh a: unmount all q: quit ?: help
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Command:
# Option1: Install via package manager from Arch, Fedora or Gentoo repos
sudo [dnf|?] install bashmount
# Option2: Install from GitHub
sudo wget -qO '/usr/local/bin/bashmount' 'https://raw.githubusercontent.com/jamielinux/bashmount/master/bashmount'
cat /usr/local/bin/bashmount # Inspect
chmod +x /usr/local/bin/bashmount # Make exectuable to all users
# Run
bashmount
sudo
, install package udisks2
.Thank you to Jivan Pal in DLN Matrix for going above and beyond helping me through this.
Disclaimer: This is an unusually raw guide because of the enormity of the subject. Itβs intended for getting the readerβs foot in the door and assumes theyβre somewhat savy with scripting, JSON, security and the basics of using Element. Do not hesitate to ask questions, I will help you.
Matrix is an open messaging protocol with clients similar to Discord and is open to 3rd-party apps by design. Thanks to their very comprehensive REST API, you can do almost anything with curl
including but not limited to building a fully featured BASH
driven chat client or telling your toaster how brown youβd like your toast.
One of the hardest hurdles was learning that most Matrix guides (including those on the Matrix site) are out of date and use deprecated APIs which often work on martix.org
but not on other deployments. Iβd highly recommend sticking to the latest API documentation.
chmod 700
your scripts before you start on them.pass
is a good example of storing tokens in encrypted files which is extremely easy to use with scripts. For a little more security you can also deliver tokens to curl
as inline variables instead of holding them in memory.We need at minimum a base url, access token and optionally a room id to use the Matrix API.
You can use something like jq
to extract values from JSON but this is intended as a pure curl
terminal guide just to get your feet wet.
# IF the account is on matrix.org use this
BaseUrl='https://matrix-client.matrix.org'
# ELIF the account is on a custom domain, get a BaseURL from a GET request
curl '<Base URL of Matrix instance without subdomain(s)>/.well-known/matrix/client/'
BaseUrl='<Extract from JSON: m.homeserver.base_url>'
# Get an access token and user id
# (This command will prompt for Username and Password inline)
# NOTE: Insure your password doesn't contain characters that'll
# escape the "" JSON encapsulation or otherwise muddle the delivery.
# (needs improvement)
curl \
-X POST \
-d '{"type":"m.login.password", "user":"'"$(read -p "Username: " U; printf '%s' "$U")"'", "password":"'"$(read -sp "Password: " P; printf '%s' "$P")"'"}' \
"${BaseUrl}/_matrix/client/r0/login"
AccessToken='<Extract from JSON: access_token>'
# Get the ID of the room you'd like to interact with
# Easiest: In the Element GUI, use the burger menu
# next to room > Settings > Advanced
RoomId='<Internal room ID>'
# You should have values similar to these by the end
BaseUrl='https://matrix-client.matrix.org'
AccessToken='MyAccessToken6AbM_stBv0sJ_Nv1oiZmr5vhf'
RoomId='!RoomTokentvPboAi:matrix.org'
# Whoami
curl \
-X GET \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer '"$AccessToken" \
"$BaseUrl"'/_matrix/client/r0/account/whoami'
# Get messages from a room
curl \
-X GET \
-H 'Authorization: Bearer '"$AccessToken" \
"$BaseUrl"'/_matrix/client/r0/rooms/'"$RoomId"'/messages?limit=10&dir=b&from='"$NextSyncToken"
NextSyncToken='<Extract from JSON: end>'
# Generate a random, collision free nonce for sending a message
# NOTE: Messages using the same nonce are ignored, it needs
# to be regenerated for every message.
TxnId=$( xxd -l 32 -c 32 -p < /dev/random )
# Send a message to a room
curl \
-X PUT \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer '"$AccessToken" \
-d '{"msgtype":"m.text", "body":"This message was sent from curl"}' \
"$BaseUrl"'/_matrix/client/r0/rooms/'"$RoomId"'/send/m.room.message/'"$TxnId"
In the Element clientβ¦
Latest API documentation: Client-Server API | Matrix Specification
Anyone have a favorite program for reading/writing JSON from the terminal?
jq
is the best tool for the job
Good oneβ¦ Itβs also in practically every repo.
Iβve heard some good things about jshon
as a faster alternative though itβs not on Fedora and I like things that are easy to add to guides.
jq -cn -r --arg body mybody '{"msgtype":"m.text", "body":$body}' {"msgtype":"m.text","body":"mybody"}
Ive found that even with larger json arrays jq acts well.
take this arrayβ¦
curl -s https://raw.githubusercontent.com/prust/wikipedia-movie-data/master/movies.json | jq ".[]"
This array of 28795 movies takes less than a second to run.
curl -s https://raw.githubusercontent.com/prust/wikipedia-movie-data/master/movies.json | jq -rc ".[] | [.title,.year,.genres[]] | @csv"
takes even less time, which means Im probably just limited to what Alacrity can render
The link was worth my visit today. Thanks!
Note the use of the β:β which prevents the variable running as a command.
# If Color DOESN'T contain a value, set it to green
unset Color
: ${Color:='green'}
echo "$Color" # Output: green
# If Color1 DOESN'T contain a value, Color2's value is green
unset Color1
Color2=${Color1:-'green'}
echo "$Color1" # Output:
echo "$Color2" # Output: green
# If Color1 DOES contain a value, Color2's value is green
Color1='red'
Color2=${Color1:+'green'}
echo "$Color1" # Output: red
echo "$Color2" # Output: green