[{"content":" POSIX: \u0026lsquo;Here string\u0026rsquo; alternative # Bash read -r VAR \u0026lt;\u0026lt;\u0026lt; \u0026quot;$(command)\u0026quot; # Dash read -r VAR \u0026lt;\u0026lt;+++ \u0026quot;$(command)\u0026quot; +++ Print unique lines without sorting This is an alternative to awk '!Line[$0]++', which prints unique lines.\nunique() { IFS_Old=$IFS IFS=$'\\n' set -- while IFS= read -r Line; do case $IFS$*$IFS in *\u0026quot;$IFS$Line$IFS\u0026quot;*) ;; # Seen *) set -- \u0026quot;$@\u0026quot; \u0026quot;$Line\u0026quot; ;; # Unique esac done printf '%s\\n' \u0026quot;$@\u0026quot; IFS=$IFS_Old } $ printf '%s\\n' foo bar baz foo baz | unique Bash builtin date # GNU date $ date '+%H:%M · %a, %b %d · %Y' # Bash $ printf '%(%H:%M · %a, %b %d · %Y)T\\n' # Output: # 23:40 · Thu, Feb 22 · 2024 Debug script recursively # Follows 'exec's bash -c \u0026quot;set -x; export SHELLOPTS; ./script\u0026quot; Pipe two commands, return the exit status of the first # Returns 1 if `maim` selection canceled, 0 otherwise mispipe \u0026quot;maim -usl -b 2 -c 0.35,0.55,0.85,0.25\u0026quot; \u0026quot;xclip -sel c -t image/png\u0026quot; Reverse an array shopt -s extdebug printf '%s\\n' \u0026quot;${ARRAY[@]}\u0026quot; shopt -u extdebug Print random array element printf '%s\\n' \u0026quot;${ARRAY[RANDOM % $#]}\u0026quot; Cycle through an array ARRAY=(a b c d) cycle_array() { printf '%s\\n' \u0026quot;${ARRAY[${i:=0}]}\u0026quot; (( i = i \u0026gt;= ${#ARRAY[@]}-1 ? 0 : ++i )) } Get first/last n element of an array printf '%s\\n' \u0026quot;${ARRAY[@]:0:n}\u0026quot; printf '%s\\n' \u0026quot;${ARRAY[@]: -n}\u0026quot; # Last n args POSIX set -- arg1 arg2 arg3 shift \u0026quot;$(($#-n))\u0026quot; printf '%s\\n' \u0026quot;${@}\u0026quot; head and tail with bash head() { mapfile -tn \u0026quot;$1\u0026quot; Line \u0026lt; \u0026quot;$2\u0026quot; printf '%s\\n' \u0026quot;${line[@]}\u0026quot; } tail() { mapfile -tn 0 Line \u0026lt; \u0026quot;$2\u0026quot; printf '%s\\n' \u0026quot;${line[@]: -$1}\u0026quot; } $ head 2 file $ tail 2 file Ternary test ## Set the value of x to y if y is greater than x. # x → variable to set # y \u0026gt; x → condition to test # ? y → if the test succeeds # : x → if the test fails (( x = y \u0026gt; x ? y : x )) Log script output # Start logging exec 6\u0026gt;\u0026amp;1 # save stdout exec 7\u0026gt;\u0026amp;2 # save stderr exec \u0026amp;\u0026gt;\u0026quot;$1\u0026quot; # Stop logging exec 1\u0026gt;\u0026amp;6 6\u0026gt;\u0026amp;- # Restore stdout exec 2\u0026gt;\u0026amp;7 7\u0026gt;\u0026amp;- # Restore stderr # Redirect error printf '%s\\n' 'Err: This is an error message.' \u0026gt;\u0026amp;2 ","permalink":"https://yusufaktepe.com/notes/shell/","title":"Shell Notes"},{"content":" Delete everything except lines containing string %v/\\(keep1\\|keep2\\)/d %g!/\\(keep1\\|keep2\\)/d Replace last occurrence in line \u0026quot; Replace last space with comma %s/.*\\zs /,/gc Run command in all Neovim instances Requires neovim-remote.\n# Switch all neovim instances to light theme $ for f in $(nvr --serverlist); do nvr --servername $f --remote-send ':set bg=light\u0026lt;cr\u0026gt;'; done ","permalink":"https://yusufaktepe.com/notes/vim/","title":"{Neo}vim Notes"},{"content":" In this post, I will share a tip on using Vifm as the default file manager.\nvifm-tab script This script allows me to use Vifm as a single instance and when I want to open a directory that utilizes xdg-open to launch the default file manager, it opens in this instance\u0026rsquo;s new tab.\nFor this script to work you need to set the server name in your vifmrc:\nlet $VIFM_SERVER_NAME = v:servername Save this script to your PATH: (I\u0026rsquo;ve added some comments inside the script so you can adjust to your needs.)\n#!/bin/sh if [ -n \u0026quot;$*\u0026quot; ]; then if [ \u0026quot;$1\u0026quot; = . ]; then # Browsers are passing . as an argument and setting PWD for dir path cmd=\u0026quot;tabnew | cd \\\u0026quot;$PWD\\\u0026quot;\u0026quot; else cmd=\u0026quot;tabnew | cd \\\u0026quot;$*\\\u0026quot;\u0026quot; fi else cmd=redraw fi if [ -n \u0026quot;$(vifm --server-list)\u0026quot; ]; then vifm --server-name vifm --remote -c \u0026quot;$cmd\u0026quot; else if [ -t 2 ]; then # When you call vifm-tab from terminal this will set terminal instance # to 'vifm' so you can assign window rule in your wm xdotool getactivewindow set_window --classname vifm \u0026amp; vifm -c \u0026quot;$cmd\u0026quot; else # You can adjust this to your terminal and shell: alacritty --class vifm -e sh -c \u0026quot;vifm -c '$cmd'; zsh\u0026quot; \u0026gt;/dev/null 2\u0026gt;\u0026amp;1 \u0026amp; fi fi Now you can open vifm with vifm-tab and pass your path as an argument to open in this single instance.\nSetting vifm-tab as a default file manager Create vifm-tab.desktop file under ~/.local/share/applications/ with the following content.\n[Desktop Entry] Categories=System;FileTools;FileManager;Utility;ConsoleOnly; Comment=Vi[m] like ncurses based file manager Exec=vifm-tab %F GenericName=File Manager Icon=vifm Name=Vifm (Tab) Terminal=true TryExec=vifm Type=Application Keywords=File;Directory;Browse; MimeType=inode/directory; Now you can set vifm-tab as the default file manager:\nxdg-mime default vifm-tab.desktop inode/directory You can find my vifm config and scripts here.\n","permalink":"https://yusufaktepe.com/posts/2021/using-vifm-as-the-default-file-manager/","title":"Using Vifm as the default file manager"},{"content":"There are a lot of APIs where you can get crypto prices. However, I used Binance because I\u0026rsquo;ve wanted to get real-time prices for the pairs I trade.\nHere\u0026rsquo;s how you can get the prices of all cryptos listed on Binance:\ncurl -s https://api.binance.com/api/v1/ticker/price We can make the output of this command more readable using jq:\ncurl -s https://api.binance.com/api/v1/ticker/price | jq -r '.[] | (.symbol + \u0026quot; = \u0026quot; + .price)' Now you can grep the output of this command to get the price of a trading pair.\n\u0026lsquo;crypto_prices\u0026rsquo; script Here\u0026rsquo;s the script I\u0026rsquo;m using to get the prices of trading pairs I follow:\n#!/usr/bin/env bash Cur=${1:-BTC|ETH|XMR} Fiat=${2:-USDT} Api=https://api.binance.com/api/v1/ticker/price shopt -s nocasematch extglob while read -ra Rate; do if [[ ${Rate[*]} =~ ^($Cur)($Fiat).*$ ]]; then Coin=${Rate[0]} Price=${Rate[1]} Price=${Price%%+(0)} Rates+=(\u0026quot;$(printf '%-9s = %s\\n' \u0026quot;$Coin\u0026quot; \u0026quot;${Price/%.}\u0026quot;)\u0026quot;) fi done \u0026lt; \u0026lt;(curl -s $Api | jq -r '.[] | (.symbol + \u0026quot; \u0026quot; + .price)' 2\u0026gt;/dev/null) printf '%s\\n' \u0026quot;${Rates[@]}\u0026quot; To get prices of SOL, ADA and MATIC you can run: crypto_prices 'SOL|ADA|MATIC' \u0026lsquo;crypto_warn\u0026rsquo; script This script gets prices from the crypto_prices and sends a notification/alarm when the given condition is met:\n#!/usr/bin/env bash # Dependencies: dunstify, ffmpeg AlarmSound=~/Music/calling.mp3 for arg in \u0026quot;$@\u0026quot;; do case $arg in -c) Cur=$2 ;; -f) Fiat=$2 ;; -le) ExprLE=\u0026quot;\u0026lt;= $2\u0026quot; ;; -ge) ExprGE=\u0026quot;\u0026gt;= $2\u0026quot; ;; -C) Continuous=true ;; -a) Alarm=true ;; -A) Alarm=true CAlarm=true ;; esac shift done while :; do P=$(crypto_prices \u0026quot;$Cur\u0026quot; \u0026quot;${Fiat:-USDT}\u0026quot;) for Expr in \u0026quot;$ExprLE\u0026quot; \u0026quot;$ExprGE\u0026quot;; do [ -z \u0026quot;$Expr\u0026quot; ] \u0026amp;\u0026amp; continue [ -z \u0026quot;$P\u0026quot; ] \u0026amp;\u0026amp; break [ \u0026quot;${Expr% *}\u0026quot; = '\u0026gt;=' ] \u0026amp;\u0026amp; Color='#2EBD85' [ \u0026quot;${Expr% *}\u0026quot; = '\u0026lt;=' ] \u0026amp;\u0026amp; Color='#E0294A' if (( $(printf '%s\\n' \u0026quot;${P##* } $Expr\u0026quot; | bc -l) )); then Expr=${Expr/\u0026lt;=/▼} Expr=${Expr/\u0026gt;=/▲} dunstify -a crypto -t 15000 -r 2001 -i money-manager-ex \\ -h string:bgcolor:$Color \u0026quot;${P/=*/$Expr}\u0026quot; if [ -n \u0026quot;$Alarm\u0026quot; ] \u0026amp;\u0026amp; [ -z \u0026quot;$Rang\u0026quot; ]; then ffplay -volume 60 -nodisp -loglevel -8 -autoexit \u0026quot;$AlarmSound\u0026quot; \u0026gt;/dev/null [ -z \u0026quot;$CAlarm\u0026quot; ] \u0026amp;\u0026amp; Rang=true fi [ -z \u0026quot;$Continuous\u0026quot; ] \u0026amp;\u0026amp; break 2 fi done sleep 5 done To get a notification/alarm when the ETH price gets above $3000 or drop below $2900 you can run: crypto_warn -c eth -le 2900 -ge 3000 -a You can find my other scripts here.\n","permalink":"https://yusufaktepe.com/posts/2021/getting-crypto-prices-from-terminal-and-setting-an-alarm/","title":"Getting crypto prices from terminal \u0026 setting an alarm"},{"content":" After trying almost all clipboard managers on Linux, I found the best solution by combining rofi and gpaste in one simple shell script.\nWith this script \u0026ndash;along with basic clipboard management\u0026ndash; you can edit past entries, archive them, or generate QR codes from them.\nIf you want to try it out, you can find it in here.\n","permalink":"https://yusufaktepe.com/posts/2021/clipboard-management-that-doesnt-suck/","title":"Clipboard management that doesn't suck"},{"content":"If you are someone like me who finds login managers unnecessary and logs into window manager from TTY, this tweak can save you time.\nEdit getty@tty1.service:\nsudo systemctl edit --full getty@tty1.service Find the line that starts with the ExecStart:\nExecStart=-/sbin/agetty -o '-p -- \\\\u' --noclear - $TERM Replace \\\\u with the username you want to log into and add -n option to agetty:\nExecStart=-/sbin/agetty -n -o '-p -- yusuf' --noclear - $TERM Now you can log into your specified user only by typing the password.\nThis only affects tty1; you can switch to another TTY to log in with a different username.\nSee man agetty for more information.\n","permalink":"https://yusufaktepe.com/posts/2020/log-in-from-tty-without-typing-username/","title":"Log in from TTY without typing username"}]