Free online editor where you can write Bash scripts, run them, take notes, and export to PDF
https://redd.it/1sd0v1g
@r_bash
A Week of Letting Bash Handle Everything
https://voidrane.substack.com/p/a-week-of-letting-bash-handle-everything
https://redd.it/1s7hej3
@r_bash
passgen — Bash password generator (DB-safe, TUI)
https://redd.it/1s6uxiv
@r_bash
-x () { local -; set -x; "$@"; }
Exhibit A in the case for "some kludges are good kludges".
https://redd.it/1s3lo2t
@r_bash
Exact timing of $PS0 and $BASHCOMMAND
I've had this line at the bottom of my ~/.bashrc for a while:
trap 'test "$BASHCOMMAND" == "$PROMPTCOMMAND" && printf "\e]2;$PWD\a" || printf "\e]2;$BASHCOMMAND\a"' DEBUG ;;
It uses a DEBUG trap to print the running command ($BASHCOMMAND) to the terminal emulator's title bar or else print the working directory ($PWD) if nothing is executing. I know some terminal emulators do this for you, but my favorite (urxvt) does not.
This has worked very well for me, but I recently learned about the $PS0 prompt, which is also run before the command executes, like a DEBUG trap, and I thought it might be a better way to implement this same thing.
It doesn't seem to be working, though, and I think the issue is in the timing of when $PS0 is shown and when $BASHCOMMAND is updated. When I add:
PS0="[\e]2;$BASHCOMMAND\a\]"
in my ~/.bashrc, the string in the terminal's title bar does update, but it's always one command behind (and the first is an odd test command). Is there any solution to this, like a way to update the $BASHCOMMAND sooner or an alternative way to get the command (from readline maybe?).
Or is the way I've already been doing this with the DEBUG trap likely still the best? I've always wondered how inefficient that is. It's all builtins, so I would hope not very, but I'm not too sure.
https://redd.it/1s4cx2x
@r_bash
...i know ...quite useless, but: ...why not watch /dev/video per bash script ? ;-P
https://redd.it/1s6gif6
@r_bash
Made a script to send reels to the group chat
https://redd.it/1s00htk
@r_bash
Why is this pattern expansion not working?
## Code snippet:
printf "%q\n" "${MAPFILE@}"
printf "\n"
printf "%q\n" "${MAPFILE@/%$'\r'}"
printf "\n"
MAPFILE=("${MAPFILE@/%$'\r'}")
printf "%q\n" "${MAPFILE@}"
printf "\n"
I wrote this code, MAPFILE basically contains line copied from clipboard.
Each line ends with a carriage return \r hence.
## Output:
$'\r'
$'# This is the first line.\r'
$'# This is the second line.\r'
''
\#\ This\ is\ the\ first\ line.
\#\ This\ is\ the\ second\ line.
$'\r'
$'# This is the first line.\r'
$'# This is the second line.\r'
1) At first you can see that each line contains an ending \r.
2) Then if I just print the expansion output directly, there are no \r at the end of each line.
3) But then if I print after assignment, it has again changed.
I want to add before any one suggests this, we can change MAPFILE manually, it is not a constant.
I have changed this array in other places as well and the program works fine.
And mind you I have tried this method of removing a character for other characters such as \t and it works.
It is for some god forsaken reason, not working only when I try to remove \r.
ALSO: I can remove \r using a loop instead where I do the same pattern expansion but line by line.
I am using git bash on windows.
If anyone has any ideas about why this isn't working, it'd be a huge help.
https://redd.it/1rzjbue
@r_bash
Can we redirect output to input using only redirection operation?
Edit (Solution): Let's first summarize the question so someone doesn't have to read the whole post.
I asked the question if the following syntax was possible.
cmd1 <&1 # something here which involved a `cmd2` to feed the output of `cmd2` as input to `cmd1`
# Yes, this the problem statement for which `|` (pipe) operator is the answer.
# But I begged the question, if we can do it specifically in this syntax, just as a curiosity.
rm asking confirmation.rm -I instead of rm, basically set an alias in .bashrc.rm always requiring confirmation when I have to delete something.yes | rm -r folder_name or printf "yes" | rm -r folder_name.rm -r src <&1 # then something herefd 1 i.e. stdout points to.rm part is an example, not a problem.stdout technically, it is using here-strings.rm -r src <<< $(printf "yes")
\
"--no-comments" \
"--no-owner" \
"--no-password" \
"--no-privileges" \
"--quote-all-identifiers"; then
exit 1
fi
}
function test_pg_restore() {
local database="$1"
local file_name="$2"
local user="$3"
local host="localhost"
local port=5432
if ! run_pg_restore \
"false" \
"${host}" \
"${port}" \
"${user}" \
"${database}" \
"--disable-triggers" \
"--exit-on-error" \
"--format=directory" \
"--jobs=9" \
"--no-acl" \
"--no-owner" \
"--no-password" \
"--no-privileges" \
"--role=${user}" "${HOME}/Desktop/${file_name}"; then
exit 1
fi
}
function test_psql() {
local command="$1"
local database="$2"
local user="$3"
local host="localhost"
local port=5432
if ! run_psql "false" "${host}" "${port}" "${user}" "${database}" "--command=${command}"; then
exit 1
fi
}
function main() {
test_createuser "test_user"
test_createdb "test_db" "test_user"
test_createdb "test_db2" "test_user"
test_psql "CREATE TABLE IF NOT EXISTS test (description TEXT);" "test_db" "test_user"
test_psql "INSERT INTO test VALUES('what an awesome day');" "test_db" "test_user"
test_psql "SELECT * FROM test;" "test_db" "test_user"
test_pg_dump "test_db" "test_user"
test_pg_restore "test_db2" "test_db" "test_user"
test_psql "SELECT * FROM test;" "test_db2" "test_user"
test_dropdb "test_db" "test_user"
test_dropdb "test_db2" "test_user"
test_dropuser "test_user"
rm -rf "${HOME}/Desktop/test_db"
}
main "$@"
```
- This is my first time writing a comprehensive bash script with functions like this
- I am looking for some critique or ways to improve what I wrote
- Anyone wanna chime in?
https://redd.it/1ryrwr1
@r_bash
flags] <user>"
return 1
fi
local -r silent="${1:-false}"
local -r postgres_host="$2"
local -r postgres_port="$3"
local -r postgres_superuser="$4"
local -r postgres_user="$5"
shift 5
local -a createuser_flags=(
"--host=${postgres_host}"
"--port=${postgres_port}"
"--username=${postgres_superuser}"
)
createuser_flags+=("$@")
[[ "${silent}" = false ]] && log_info "Executing createuser on host: ${postgres_host}, port: ${postgres_port}, username: ${postgres_superuser} with flags: ${createuser_flags[*]}"
if createuser "${createuser_flags[@]}" "${postgres_user}"; then
[[ "${silent}" = false ]] && log_info "createuser command executed successfully"
return 0
else
[[ "${silent}" = false ]] && log_error "createuser command execution failed"
return 1
fi
}
function run_dropdb() {
if [[ -z "$(command -v dropdb)" ]]; then
log_error "dropdb command not found. Please ensure PostgreSQL client is installed."
return 1
fi
if [[ "$#" -lt 5 ]]; then
log_error "Usage: run_dropdb <silent> <host> <port> <user> <database> [additional dropdb flags]"
return 1
fi
local -r silent="${1:-false}"
local -r postgres_host="$2"
local -r postgres_port="$3"
local -r postgres_user="$4"
local -r postgres_database="$5"
shift 5
local -a dropdb_flags=(
"--host=${postgres_host}"
"--port=${postgres_port}"
"--username=${postgres_user}"
)
dropdb_flags+=("$@")
[[ "${silent}" = false ]] && log_info "Executing dropdb on database: ${postgres_database}, host: ${postgres_host}, port: ${postgres_port}, username: ${postgres_user} with flags: ${dropdb_flags[*]}"
if dropdb "${dropdb_flags[@]}" "${postgres_database}"; then
[[ "${silent}" = false ]] && log_info "dropdb command executed successfully"
return 0
else
[[ "${silent}" = false ]] && log_error "dropdb command execution failed"
return 1
fi
}
function run_dropuser() {
if [[ -z "$(command -v dropuser)" ]]; then
log_error "dropuser command not found. Please ensure PostgreSQL client is installed."
return 1
fi
if [[ "$#" -lt 5 ]]; then
log_error "Usage: run_dropuser <silent> <host> <port> <superuser> [additional createuser flags] <user>"
return 1
fi
local -r silent="${1:-false}"
local -r postgres_host="$2"
local -r postgres_port="$3"
local -r postgres_superuser="$4"
local -r postgres_user="$5"
shift 5
local -a dropuser_flags=(
"--host=${postgres_host}"
"--port=${postgres_port}"
"--username=${postgres_superuser}"
)
dropuser_flags+=("$@")
[[ "${silent}" = false ]] && log_info "Executing dropuser on host: ${postgres_host}, port: ${postgres_port}, username: ${postgres_superuser} with flags: ${dropuser_flags[*]}"
if dropuser "${dropuser_flags[@]}" "${postgres_user}"; then
[[ "${silent}" = false ]] && log_info "dropuser command executed successfully"
return 0
else
[[ "${silent}" = false ]] && log_error "dropuser command execution failed"
return 1
fi
}
function run_pg_dump() {
if [[ -z "$(command -v pg_dump)" ]]; then
log_error "pg_dump command not found. Please ensure PostgreSQL client is installed."
return 1
fi
if [[ "$#" -lt 5 ]]; then
log_error "Usage: run_pg_dump <silent> <host> <port> <user> <database> [additional pg_dump flags]"
return 1
fi
local -r silent="${1:-false}"
local -r postgres_host="$2"
local -r postgres_port="$3"
local -r postgres_user="$4"
local -r postgres_database="$5"
shift 5
local -a pg_dump_flags=(
"--dbname=${postgres_database}"
"--host=${postgres_host}"
"--port=${postgres_port}"
"--username=${postgres_user}"
)
pg_dump_flags+=("$@")
[[ "${silent}" = false ]] && log_info "Executing pg_dump on database: ${postgres_database}, host: ${postgres_host}, port: ${postgres_port}, username: ${postgres_user} with flags: ${pg_dump_flags[*]}"
if pg_dump
need help getting sgrep to work in a script file
this command will find all references to emdash in a swath of files and report back which files contain the reference.
sgrep -o '%r\n' '"\"" _quote_ "\"" in ("name[Group1]" .. "\n" in outer("{" .. "}" containing "emdash"))' /usr/share/X11/xkb/symbols/??
read sym$sym in place of the fixed string emdashcontaining "$sym"Parse error in command line expression column 77 :
Invalid character
" _quote_ "\"" in ("name[Group1]" .. "\n" in outer("{" .. "}" containing $sym))
^
No query to evaluate. Bailing out.
containing "$(echo $sym)"sgrep not capable of evaluating variables? or what?
Environment Variables
I am currently trying to understand bash and am learning with linuxjourney. However, I am now kind of stuck at understanding environment variables. Can someone tell me if I am understanding this right?
Basically, environment variables are variables, that store information. Now this can be either information (like PATH stores it) that points toward certain directories from where the shell would get the program needed for a command or it is a variable storing information about which directory I am currently in like PWD variable and so on. These variables can either temporarly changed by "export PATH = /example" which would only change the variable for the current session or they can be permanently changed by altering the configuration files.
Also the environment variables are built from these configuration files on booting (or opening shell idk pls help) and can as mentioned be configured to behave different permanently by altering the config files.
What I still completely struggle with is why does one variable actively tell the shell where to look for program files like PATH and other are just storing information like PWD. ChatGPT said that there are functional/operational variables like PATH and informational/state variables like PWD. Can someone confirm the validity of this information?
As you see I am completely new to this and I am really lost so any help will make me happy, thanks!
https://redd.it/1ry5vbp
@r_bash
for loop not indexing stuff in the {}'s
i can make a for loop like this
for i in {1..13} ; do
echo $i
done
len=13for i in {1..$len} ; do
echo $i
done
{1..13}
AI written in BASH? It exists!
Someone actually created an AI (GPT) in BASH!
https://github.com/ResonantEntropy/bashGPT
It is not a wrapper around curl.. It's a full GPT!
LOL! This is intense!
https://redd.it/1s8hiwa
@r_bash
Terminal Native API Testing Tool is LIVE!
https://preview.redd.it/gq2fehb401sg1.png?width=1233&format=png&auto=webp&s=84566c1673098db1088664090ad091e0c01a3a0d
Hey guys!
Rust based API Testing Tool is now live,
# Y'all can download it from here: Volt
This is a minimalistic API testing tool right in the terminal itself which has a blazingly fast response window. It scans source files and lists every route instantly — axum, express, fastapi, next.js, and more so that you do not need to write the Endpoints or Base URLs manually.
Do check it out and let me know your thoughts.
The Binaries are available for MacOS, Linux, and Windows on the website. Feel free to drop issues if you find any.
https://redd.it/1s72ksw
@r_bash
Could someone please review my scripting and give me criticism?
I made a script to manage my dotfiles on linux (arch btw).
Link to repo
https://codeberg.org/Flan-Angel/Dawtfiles/src/branch/main
Link to script
https://codeberg.org/Flan-Angel/Dawtfiles/src/branch/main/PushToSYS.sh
Tysm if you do end up checking it out :)
https://redd.it/1s42scy
@r_bash
Functions from my bashrc
My list of functions has gotten pretty long, thought maybe I'd share, [as asked](https://www.reddit.com/r/bash/comments/1s3lo2t/comment/ocgkhi1/). Share some interesting functions of your own, or any feedback you think I could use.
\>> [bashrc excerpt gist](https://gist.github.com/ekipan/1c2e5a6164fbe7601b32e089d889994c), and [permalink at time of post](https://gist.github.com/ekipan/1c2e5a6164fbe7601b32e089d889994c/adac6cb830131238a3666390d7574ec8a95f15be)
# a few of them:
e() { echo >&2 "$@"; "$@"; } # echo and run
hl() { bat -Ppl "${1:-help}"; } # highlight eg: find --help | hl
iftty() { if [[ -t "$1" ]]; then "${@:2}"; else cat; fi; }
opts() { iftty 0 "$@" --help |& rg "^\s*-" | hl; } # eg: opts find
# see gist for the rest.
A few I use _constantly_: gits() h() opts(). A ps1() that puts a newline if the last command didn't, so my prompt is on the left margin while scrolling back. A bit of whimsy like q() that I [adapted from a reddit post](https://www.reddit.com/r/zsh/comments/1rs6gcn/). I like the interface I designed for the path() function but since I only used it exactly once in my bashrc I just took it back out.
My style is definitely a lot more dense and nongeneric than most people or LLMs would like, but I own these functions and dense, direct code is better IMO.
**Background:** After my old Windows Thinkpad started getting a bit sick, I switched to using my Steam Deck as my main PC, with a dock, TV, and bluetooth keyboard. It seems a pretty good Arch flavor, and I wasn't entirely new to Linux, but I've learned a lot. One pain point is lack of manpages, so one of the first things I put in my .bashrc was a bunch of aliases to open my browser or curl from <https://cheat.sh>.
I had a ten-year-old account ended up shadowbanned, presumably because I posted a bashrc excerpt with URLs in it, maybe also because I'd forgotten about the account for years, idk. Thus the pastebin: I'm wary of posting too much code directly.
https://redd.it/1s3u7f5
@r_bash
Function on .bashrc
Hello! I trying to add this function on my bashrc, but because of the quotes and single quotes, it's returning this error:
\-bash: .bashrc: line 142: unexpected EOF while looking for matching `''
\-bash: .bashrc: line 145: syntax error: unexpected end of file
The function is this one:
140 dwdb() {
141 local query="SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' ORDER BY TABLE_NAME;"
142 sqlcmd -S link -d table -U user -P 'password' -C -Q "$query"
143 }
https://redd.it/1s5emg1
@r_bash
How to improve bash script which is collecting data every 10 seconds
I wrote a script which is collecting data from solar inverter every 10 seconds for 5 minutes, it does some math and send data to [emoncms](https://github.com/emoncms/emoncms). It does work but is not optimal in term of CPU usage, it is running on SBC and consume roughly 80% of CPU time. My question is how can I initiate next data collection without checking script running time in a loop. Below is simplified script. I need to improve line 7.
#!/bin/bash
set -o pipefail
IFS=$''
samples="0"
nr="0"
while [ $SECONDS -lt 292 ]; do #5min-8s
if [[ (( $(( (samples - 1) * 10 + 10 )) == $SECONDS )) || (( 0 == $SECONDS )) ]]; then
((samples++))
timestart=$SECONDS
output="$(./inverter_poller --run-once)" # get data from inverter
timeend=$SECONDS
echo ${output} > /var/log/inverter.last
rs232time=$((timeend - timestart)) # usually it is 6-7 seconds
if (( rs232time < 17 )); # inverter is not responding if it is 17s or more
then
gridv=`echo ${output} | grep grid_voltage | tr -d " "_\",:[:alpha:]`
***more data extraction and math***
else
echo inverter not responding >> /var/log/inverter.last
fi
looptime=$((SECONDS - timestart))
echo "time": $looptime >> /var/log/inverter.last
fi
done
***boring data processing and sending to emoncms was here***
https://redd.it/1s6dsf2
@r_bash
I want to share my unit test lib for TUI apps
https://github.com/fissible/ptyunit
Most bash test frameworks only assert on stdout. That breaks down as soon as your script:
\- renders to /dev/tty
\- uses cursor movement / ANSI
\- handles arrow keys or interactive input
ptyunit runs your script inside a real pseudoterminal, sends keystrokes (UP, DOWN, ENTER, etc), and lets you assert against what a user would actually see.
out=$(python3 pty_run.py examples/confirm.sh RIGHT ENTER)
assert_contains "$out" "Cancelled"
I originally built this because I couldn’t reliably test a git diff TUI I was working on. Capturing /dev/tty output made it possible to catch layout and rendering issues.
It also doubles as a minimal assertion framework, so you can use it standalone instead of pulling in another dependency.
Would be curious if anyone else here is testing interactive bash tools, or if you’ve run into this gap before.
Install:
\- bpkg install fissible/ptyunit
\- brew tap fissible/tap && brew install ptyunit
Feedback welcome.
https://redd.it/1s048iz
@r_bash
Practice Examples
Ive been coding in python on windows for a while and consider it my main programming language, but Ive been intending to pick up another programming language for a while ( I was going to move to c / c++)
Tell me why, after installing Ubuntu on wsl to try it out
and my friend started teaching me some bash
is it literally so fun to write?
And like its kind of useful too because I can just make functions for navigating my terminal and new aliases...
Anyways Im looking for practice problems to go over, suitable for a beginner so I can keep learning, if you have any suggestions.
https://redd.it/1rzqod6
@r_bash
This bash program isn't closing the file descriptor
printf "This is the first line\r\nThis is the second line\r\n" > "test.txt"
: {fd}< "test.txt"
read <&$fd-
printf "$?; $REPLY\n"
read <&$fd-
printf "$?; $REPLY"
0; This is the first line
0; This is the second line
>&fd- and why its effect goes away after one command.printf "hey" >&3 would lead to stdout permanently becoming a copy of fd 3 which isn't ideal at all. Therefore, bash automatically restores the state before the redirect after the command is complete.>&fd- then?# Run in one terminal
mkfifo my_pipe
cat my_pipe
# Run in a separate terminal
exec 3> my_pipe
(
echo "Worker is doing some fast work....
sleep 100 > /dev/null &
) >&3 & # <--- HERE IS THE COPY (>&3)
exec 3>&-
echo "Main script finished."
fd 3, sleep can potentially write to it which leads to cat waiting for 100 seconds before being complete. This leads to terminal 1 being stuck for 100 seconds.>&3-, we would have made a move operation and hence there would be no open fd to write to for sleep which leads to cat exiting instantly.
I built a free CLI journaling tool for developers - just type "journal" and start writing
Every journaling app I've tried adds friction. Open the app, wait for sync, pick a template. By the time you're ready to write, the thought is gone.
journalot is a bash CLI that creates daily markdown files and auto-commits to git. Quick capture mode lets you log thoughts without opening an editor. Search finds old entries with context highlighting.
https://github.com/jtaylortech/journalot
Been using it daily for months now. Consistency comes from friction removal, not motivation.
https://i.redd.it/r7taegzq9ppg1.gif
https://redd.it/1rwp2y4
@r_bash
"${pg_dump_flags[@]}"; then
[[ "${silent}" = false ]] && log_info "pg_dump command executed successfully"
return 0
else
[[ "${silent}" = false ]] && log_error "pg_dump command execution failed"
return 1
fi
}
function run_pg_restore() {
if [[ -z "$(command -v pg_restore)" ]]; then
log_error "pg_restore command not found. Please ensure PostgreSQL client is installed."
return 1
fi
if [[ "$#" -lt 6 ]]; then
log_error "Usage: run_pg_restore <silent> <host> <port> <user> <database> [additional pg_restore flags] <filename>"
return 1
fi
local -r silent="${1:-false}"
local -r postgres_host="$2"
local -r postgres_port="$3"
local -r postgres_user="$4"
local -r postgres_database="$5"
local -r filename="$6"
shift 5
local -a pg_restore_flags=(
"--dbname=${postgres_database}"
"--host=${postgres_host}"
"--port=${postgres_port}"
"--username=${postgres_user}"
)
pg_restore_flags+=("$@")
[[ "${silent}" = false ]] && log_info "Executing pg_restore on database: ${postgres_database}, host: ${postgres_host}, port: ${postgres_port}, username: ${postgres_user} with flags: ${pg_restore_flags[*]}"
if pg_restore "${pg_restore_flags[@]}" "${filename}"; then
[[ "${silent}" = false ]] && log_info "pg_restore command executed successfully"
return 0
else
[[ "${silent}" = false ]] && log_error "pg_restore command execution failed"
return 1
fi
}
function run_psql() {
if [[ -z "$(command -v psql)" ]]; then
log_error "psql command not found. Please ensure PostgreSQL client is installed."
return 1
fi
if [[ "$#" -lt 5 ]]; then
log_error "Usage: run_psql <silent> <host> <port> <user> <database> [additional psql flags]"
return 1
fi
local -r silent="${1:-false}"
local -r postgres_host="$2"
local -r postgres_port="$3"
local -r postgres_user="$4"
local -r postgres_database="$5"
shift 5
local -a psql_flags=(
"--dbname=${postgres_database}"
"--host=${postgres_host}"
"--port=${postgres_port}"
"--username=${postgres_user}"
)
psql_flags+=("$@")
[[ "${silent}" = false ]] && log_info "Executing psql on database: ${postgres_database}, host: ${postgres_host}, port: ${postgres_port}, username: ${postgres_user} with flags: ${psql_flags[*]}"
if psql "${psql_flags[@]}"; then
[[ "${silent}" = false ]] && log_info "psql command executed successfully"
return 0
else
[[ "${silent}" = false ]] && log_error "psql command execution failed"
return 1
fi
}
```
- This is how I use the above script
**test.sh**
```
#!/usr/bin/env bash
# shellcheck source=/dev/null
source "${HOME}/Desktop/utils/src/postgres_utils.sh"
function test_createdb() {
local database="$1"
local user="$2"
local host="localhost"
local port=5432
if ! run_createdb \
"false" \
"${host}" \
"${port}" \
"${user}" \
"${database}" \
"--encoding=UTF-8" \
"--owner=${user}" \
"--username=${user}"; then
exit 1
fi
}
function test_createuser() {
local user="$1"
local host="localhost"
local port=5432
local superuser="root"
if ! run_createuser \
"false" \
"${host}" \
"${port}" \
"${superuser}" \
"${user}" \
"--createdb" \
"--echo" \
"--inherit" \
"--login" \
"--no-createrole" \
"--no-replication" \
"--no-superuser"; then
exit 1
fi
}
function test_dropdb() {
local database="$1"
local user="$2"
local host="localhost"
local port=5432
if ! run_dropdb \
"false" \
"${host}" \
"${port}" \
"${user}" \
"${database}" \
"--if-exists" \
"--no-password"; then
exit 1
fi
}
function test_dropuser() {
local user="$1"
local host="localhost"
local port=5432
local superuser="root"
if ! run_dropuser \
"false" \
"${host}" \
"${port}" \
"${superuser}" \
"${user}" \
"--echo" \
"--if-exists"; then
exit 1
fi
}
function test_pg_dump() {
local database="$1"
local user="$2"
local host="localhost"
local port=5432
if ! run_pg_dump \
"false" \
"${host}" \
"${port}" \
"${user}" \
"${database}" \
"--compress=9" \
"--encoding=UTF-8" \
"--file=${HOME}/Desktop/${database}" \
"--format=directory" \
"--jobs=9" \
"--no-acl"
Any of you want to critique the postgres utils script I wrote?
**`logger_utils.sh`**
```
#!/usr/bin/env bash
#
# Contains functions for logging different types of messages.
#######################################
# Determine if the terminal supports color.
# Arguments:
# None
# Returns:
# 0 if color is supported, 1 otherwise.
#######################################
function supports_color() {
# stderr is a terminal?
[[ -t 2 ]] || return 1
# Terminal claims color support
[[ -n "${TERM:-}" && "${TERM}" != "dumb" ]] || return 1
# Respect NO_COLOR standard
[[ -z "${NO_COLOR:-}" ]] || return 1
return 0
}
#######################################
# Define color constants based on terminal support.
# Globals:
# COLOR_RED, COLOR_GREEN, COLOR_NONE
#######################################
if supports_color || [[ -n "${force_color:-}" ]]; then
readonly COLOR_RED='\033[0;31m'
readonly COLOR_GREEN='\033[0;32m'
readonly COLOR_YELLOW='\033[0;33m'
readonly COLOR_NONE='\033[0m'
else
readonly COLOR_RED=''
readonly COLOR_GREEN=''
readonly COLOR_YELLOW=''
readonly COLOR_NONE=''
fi
#######################################
# Internal logging function.
# Arguments:
# 1: Message string
# 2: Status string (e.g., INFO, ERROR)
# 3: Color escape code
# Outputs:
# Writes formatted log to stderr.
#######################################
function log_message() {
local -r message="$1"
local -r status="${2:-INFO}"
local -r color="${3:-${COLOR_NONE}}"
local -r timestamp="$(date +"%Y-%m-%dT%H:%M:%S%z")"
# Output to stderr (>&2) as per the guide's recommendation for diagnostic info.
printf "[%s] [%b%s%b] %s\n" \
"${timestamp}" \
"${color}" "${status}" "${COLOR_NONE}" \
"${message}" >&2
}
#######################################
# Log an error message in red.
# Arguments:
# 1: Message string
#######################################
function log_error() {
log_message "$1" "ERROR" "${COLOR_RED}"
}
#######################################
# Log an info message in green.
# Arguments:
# 1: Message string
#######################################
function log_info() {
log_message "$1" "INFO" "${COLOR_GREEN}"
}
#######################################
# Log a warning message in yellow.
# Arguments:
# 1: Message string
#######################################
function log_warn() {
log_message "$1" "WARN" "${COLOR_YELLOW}"
}
```
**`postgres_utils.sh`**
```
#!/usr/bin/env bash
#
# Contains functions for common postgresql database operations
# shellcheck source=/dev/null
source "${HOME}/Desktop/utils/src/logger_utils.sh"
function run_createdb() {
if [[ -z "$(command -v createdb)" ]]; then
log_error "createdb command not found. Please ensure PostgreSQL client is installed."
return 1
fi
if [[ "$#" -lt 5 ]]; then
log_error "Usage: run_createdb <silent> <host> <port> <user> <database> [additional createdb flags]"
return 1
fi
local -r silent="${1:-false}"
local -r postgres_host="$2"
local -r postgres_port="$3"
local -r postgres_user="$4"
local -r postgres_database="$5"
shift 5
local -a createdb_flags=(
"--host=${postgres_host}"
"--port=${postgres_port}"
"--username=${postgres_user}"
)
createdb_flags+=("$@")
[[ "${silent}" = false ]] && log_info "Executing createdb on database: ${postgres_database}, host: ${postgres_host}, port: ${postgres_port}, username: ${postgres_user} with flags: ${createdb_flags[*]}"
if createdb "${createdb_flags[@]}" "${postgres_database}"; then
[[ "${silent}" = false ]] && log_info "createdb command executed successfully"
return 0
else
[[ "${silent}" = false ]] && log_error "createdb command execution failed"
return 1
fi
}
function run_createuser() {
if [[ -z "$(command -v createuser)" ]]; then
log_error "createuser command not found. Please ensure PostgreSQL client is installed."
return 1
fi
if [[ "$#" -lt 5 ]]; then
log_error "Usage: run_createuser <silent> <host> <port> <superuser> [additional createuser
Tip Stop mashing the Up arrow: Filtered History Search with Alt+Up/Down
If you have a 100-character xrandr command or a complex docker string that you use intermittently, Ctrl+R can be a clunky way to find it. Instead, you can configure Bash to perform Incremental History Searching.
This allows you to type the first few letters of a command (e.g., xr) and use a modifier key to cycle only through previous commands that start with those letters.
1. The Configuration Add these lines to your ~/.inputrc.
2. We use the Alt (Meta) key to avoid overwriting the standard "Up/Down" scrolling behavior:Bash# Alt+Up: Search forward or backward for commands starting with what you've typed:"\e[1;3A": history-search-backward# Alt+Down: Search backward for commands starting with what you've typed: "\e[1;3B": history-search-forward
Wait, why not just use Ctrl+S to search forward? Standard terminals use Ctrl+S for "XOFF" (flow control), which instantly freezes your terminal output (requiring Ctrl+Q to unfreeze). While you can disable this with stty -ixon, mapping forward-search to Alt+Down is a much cleaner "modern" solution that doesn't mess with legacy TTY settings.
2. Apply it Instantly You don't need to reboot or restart your shell. Tell the Readline library to reload its configuration immediately:Bashbind -f ~/.inputrc
3. The Workflow Type xrandr (or even just xr).
Press Alt+Up.
It will skip over every ls, cd, and git command in your history and jump straight to your last complex xrandr call.
Press Alt+Up again to go further back in time through only the xrandr entries.
Why Alt+Up/Down? Most tutorials suggest mapping the standard Up/Down arrows (\\e[A), but that breaks the ability to simply scroll back through the last few (unfiltered) commands. Mapping it to the Alt modifier gives you the best of both worlds: standard history for quick tasks, and filtered search for the complex stuff.
https://redd.it/1rx8pz3
@r_bash
How do you print "Here document" or "Here Strings" directly?
Edit (Solution): There are two solutions here, depending on the case in which you are.
- Case 1: You use Here Document to print some multiline text.
Don't do that.
Instead, you can just do this:
printf "%s\r\n"\
"This is the first line."\
"This is the second line."
# This solution has just one annoyance which is that you have to enclose all lines in double quotes and end with a slash.
# But compare this to here documents which don't allow any special characters to be used, sort of.
\ to write a command in multiple lines.
{ printf "%s\n" "$(< /dev/stdin)"; } <<-EOF
This is first line.
This is second line.
This is third line.
EOF