r_bash – Telegram
Why printf over echo? (noob question)

I regularly come across comments in which it's recommended to rather use printf than echo in shell noscripts. I wonder why that is.
And in this regard: would it be worth the time and energy to replace all the echos in a working noscript with printf?
And last question: do people usually get annoyed when you use both, echo and printf in one noscripts (a published noscript that is)?

https://redd.it/1519wby
@r_bash
Pinging periodically using a noscript and crabtab

In the past week or so my home internet feels unstable. So I created the following little noscript to check it out:

'''bash
#!/bin/bash

# Change the destination log file path
log_file=~/Code/PingsLogger/pings.log

# Replace 'your_router_ip' with the IP address of your router or the server you want to ping
router_ip='8.8.8.8'

# Ping the router and record the result to the log file
ping_result=$(ping -c 1 $router_ip | grep 'bytes from' | cut -d '=' -f 4)
current_time=$(date +"%Y-%m-%d %H:%M:%S")

if [ -n "$ping_result" ]; then
echo "$current_time - Lag: $ping_result ms" >> $log_file
else
echo "$current_time - Request timed out" >> $log_file
fi
'''

Saved it to a file named [pings.sh](https://pings.sh) (called chmd and such), initiated a file name pings.log and I added to crontab the following line:
`* * * * * ~/Code/PingsLogger/pings.sh`

When I run the noscript manually it does the job and adds a new line to the log but when the crontab runs it it always adds only 'Request timed out' to the log file.


Can someone help me understand what am I doing wrong? :(


https://redd.it/152sx45
@r_bash
My personal trick to improve "test" command readability

I know it may not be a problem for bash noscript veterans, but for someone like me who write bash noscripts not quite often, bash test operators are too concise to be memorized long term or read. As of writing, I only remember for certain simple ones like "-e" for "file exists", "-f" for "file is regular file", "-d" for "file is directory". I remember several times I mistook "-n" for "file not exists", however in fact, there is no test operator for "file not exists". If I need to write some bash noscript after one week or two since I last wrote some bash noscripts, I certainly have to check 'man test' again because

1. I forget what some operators represents
2. I remember what some operators represents, but at this time I'm not sure I remember it right
This scenario has occurred several times on me, and it is annoying.

The other problem is about readability. Bash's conciseness is good for commandlining, but not for readability. Whenever I encounter a test operator, there is a mapping process in my brain to map the letter to the function it performs. Some mapping may be quick, like "-d" for "is directory" since "d" is the first letter of "directory", but some are not, like "s" for "file is not zero size". I think they just randomly picked a remaining letter for this. Whether quick or not, there is this extra mapping going on. And this is annoying. If I'm using some other object-oriented programming language, there must be some function like isDirectory(). And this is straightforward, no extra mental mapping.

So I use a simple trick to help me.
If I'm gonna use a test operator, I use a variable with a denoscriptive name to replace it.
For example, instead of

if test -h '/etc/somefile'; then
echo it is a symlink
fi

I use this

fileissymlink='-h'

if test $fileissymlink '/etc/somefile'; then
echo it is a symlink
fi

This is more readable and fewer magic letters!
This depends on personal preferences. Some may not like this verbosity, but I do.

In order to keep consistency within all my bash noscripts. I have to create definitions for all operators that need to be replaced. like this
> fileisexecutable='-x'

> stringisnotempty='-n'

> file
issymlink='-h'

> ...


Now, in all my bash noscripts, I include the needed definitions in the file.
For some operators, like "-eq", "-gt" and so on, as they are denoscriptive enough, I just use them.

But there is so much extra typing! Luckily, many text editors today can be extended to suit personal needs.
I use emacs. First I added extra code completions. Now when I type "$fi", a popup completion list shows all the candidates I have defined, like:
> file
issymlink

> file
isexecutable

> file
exists

> fileispipe

> fileissocket

> fileisreadable

> fileisterminal

> ...

I just choose what I need.

Second, I don't want to manually type the definitions. I created a function to automatically run before save the bash file. It will search my bash noscript. If it found one, it will add the definition after the shebang.

Great. If now I want to write a if statement to test whether a file is connected to a terminal.
I just type if test $fi, select "fileisterminal" from completion list, finish the if statement, save the file. file_is_terminal='-t' is automatically added after shebang. I don't need to care about choosing the right magic letter anymore, and it is so readable.

The readability is only applied to noscripts written by myself. If I'm going to read others' bash noscripts, I'm pretty sure I have to face the magic letters again. Luckily, I don't quite often read others' bash noscripts.

https://redd.it/152uw68
@r_bash
Bash command error

Hi, I don't know bash at all, and GPT4 was unable to help...
I'm trying to run this bash command:
`sed -i .tmp -E 's/"(version)"[ ]*:[ ]*".*"/"\1": "1.8.4"' bower.json`
and getting this error:
`sed: -e expression #1, char 1: unknown command: \`.'`


Any idea?

https://redd.it/152x6lg
@r_bash
I could use some help with automation for git pull and passing username and password

Hi,

I would like to automate an update of my dot files repo and since git keeps credentials in plain text, I would like to avoid that and pass the username and password each time (credentials will be retrieved from keepassxc)

I cannot figure out, how to feed credentials to the git prompt, here is my test noscript (please forget about the keepassxc part for now):

#!/bin/bash

user="user"
pass="abc123"

echo "DEBUG user: $user"
echo "DEBUG pass: $pass"

cd ./tst2/tst
(echo $user; echo $pass) | git pull

It doesn't work, git still waits for me to pass the username. I don't understand why, because I've used the same structure (echo $var1; echo $var2 ...) | <command> in different examples, like automation of drives partitioning with fdisk, and it worked just fine.

https://redd.it/1536qwd
@r_bash
syntax for hash comparisons. newbie help

what is the code/syntax to compare:

i have a string. i want to hash it and compare that hash to a hash stored in a file

something like:

if [ "string" | sha256sum -eq cat file.txt \] ; then

&#x200B;

https://redd.it/153hs6y
@r_bash
To run this bash noscript inside a cron job every 4 hrs, what is the safest way to put your postgres password here?
https://redd.it/153xtfn
@r_bash
Login to remote machine, execute commands, save them in text file in source machine

Will try to make this as simple as possible, here is the scenario I need to achieve.

1. From a linux box login to another machine via SSH (this machine might not be linux based, at times is propriatery syntax)
2. Execute set of commands on the remote machine and save the output let's say from screen inside a text file on the original machine.

The way this is being done at the moment is using "expect", and sending the password in plain text inside the shell noscript.

As part of security improvements i am taking care of, the task is to make this remote login password less, no password shall be passed over the noscript in plain text.

&#x200B;

Ideally this should be done using keys.

&#x200B;

How would this be done by still retaining the expect noscript since i run "expect"/"send" commands to the remote machine.

&#x200B;

I am also open to different ideas you might have, maybe from experience.

&#x200B;

TIA

https://redd.it/153xwll
@r_bash
"head" command changes the output of another command visually in an unexpected way

Hi there! I wanna get list of all scenes from Blender 3D file (.blend), I've wrote this command:

blender -b test.blend --python-expr 'import bpy

for name in scene.name for scene in list(bpy.data.scenes):
print(name)'

For my .blend file it outputs the following text to stdout:

Color management: using fallback mode for management
Color management: Error could not find role data role.
Blender 3.0.1
Color management: scene view "Filmic" not found, setting default "Standard".
Read blend: /home/emilyseville7cfg/Documents/open-source/other/forks/fish-shell/test.blend
Scene
Scene.001

Blender quit

As I don't know how to get rid of all this garbage output (all except two scene names) I decided to use head/tail for this task. But when I just run head:

blender -b test.blend --python-expr 'import bpy

for name in scene.name for scene in list(bpy.data.scenes):
print(name)' | head --lines 100 # 100 is used as a test case

it's output confuses me:

Scene
Scene.001
Color management: using fallback mode for management
Color management: Error could not find role data role.
Blender 3.0.1
Color management: scene view "Filmic" not found, setting default "Standard".
Read blend: /home/emilyseville7cfg/Documents/open-source/other/forks/fish-shell/test.blend

Blender quit

So my question is: how it is possible that piping through modifies output visually while all data from blender is sent to just one stream stdout? I've checked > /dev/null discards any output here. I feel that I'm misunderstanding something. I don't think that it's a bug because the same thing reproduces in a Fish shell too and in Nushell, it's more likely I miss something.

https://redd.it/155clzz
@r_bash
Is it possible to have "select... do... done" timeout if no selection is made?

I need the following to continue with the rest of the noscript if a selection is not made within a pre-set time period. Or automatically select a default choice.

#!/usr/bin/env bash

PS3="Select your M.2 Card: "
options=("M2D20" "M2D18" "M2D17")
select choice in "${options@}"; do
case "$choice" in
M2D20)
card=m2d20
break
;;
M2D18)
card=m2d18
break
;;
M2D17)
card=m2d17
break
;;
esac
done

If that's not possible I can think of other solutions.

https://redd.it/155fpu7
@r_bash
Generic Bash Script Args - Starting Point?

I think having a good starting point is important. I think any noscript that needs to have args needs to take long and short as well as take them in any order.


Here's what I think that starting point looks like, are there any improvements I should think about?


#!/usr/bin/env bash
###################################################################
# Script Name : bash_getops_any_order_7.sh
# Version : 0.1
# Date :
# Denoscription :
# Args : -c <_copy-from_> -r <_creation_> -n <_var-num_> -s <_step_> [-h <_help_>]
# --copy-from <_copy-from_> --creation <_creation_> --var-num <_var-num_> --step <_step_> [--help]
# Author :
# Email :
# Documentation :
# Git / SVN :
# Jira :
# Copyright :
###################################################################
## shellcheck
#
# TODO:

# make sure we have decent error handling for bash noscripts
set -o errexit -o noglob -o nounset -o pipefail

###################################################################
#### Test all Dependancies
_SCRIPTNM="${0##*/}"

function _printf_yel () {
printf "\e[33m%-6s\e[m %s\n" "${@}"
}

function _printf_yel_n () {
printf "\e[33m%-6s\e[m %s" "${@}"
}

function _printf_red () {
printf "\e[91m%b\e[0m %s\n" "${@}"
}

_SET_EXIT=0
for _DEPEN in grep git awk vim rm ; do
hash "${_DEPEN}" >/dev/null 2>&1 || {
_SET_EXIT=1
} ; done
if [[ "${_SET_EXIT}" -eq "1" ]]; then
echo " CRIT: ERROR Script" "${_SCRIPTNM}" "is Missing Dependancies"
echo "Missing - please install any required packages for the following dependencies"
_printf_yel "${_DEPEN}"
exit 1
fi
###################################################################
#### Test bash version as macos ships with somethng from 1800!
if [[ -z "${BASH_VERSION}" ]]; then
echo "Can't find bash version _ Bash v4+ is a requirement"
exit 1
else
if [[ ! "${BASH_VERSION:0:1}" -gt "3" ]]; then
echo "current version = ${BASH_VERSION} required version = 4.+"
echo "Bash version is too low - please use a newer version for this noscript"
exit 1
fi
fi
###################################################################

function _usage () {
echo "Usage: $(basename "$0") -c <_copy-from_> -r <_creation_> -n <_var-num_> -s <_step_> [-h <_help_>"] >&2
echo "or"
echo "Usage: $(basename "$0") --copy-from <_copy-from_> --creation <_creation_> --var-num <_var-num_> --step <_step_> [--help]" >&2
exit 0
}

_VERSION="0.1"
_date=$( date +'%d %b %Y %H:%M:%S' )

#### Parse options and arguments with getopt
if ! args=$( getopt --options c:r:n:s:h --longoptions copy-from:,creation:,var-num:,step:,help -- "$@" ); then
echo "Error: Failed to parse options and arguments." >&2
exit 1
fi

#### Initialize variables with default values
copyfrom=""
creation=""
varnum=""
step=""

# Process options and arguments
eval set -- "${args}"
while [[ "${#}" -gt 0 ]]; do
case "$1" in
-c|--copy-from)
copyfrom="${2}"
shift 2
;;
-r|--creation)
creation="${2}"
shift 2
;;
-n|--var-num)
varnum="${2}"
shift 2
;;
-s|--step)
step="${2}"
shift 2
;;
-h|--help)
_usage
;;
--)
shift
break
;;
*)
echo "Error: Invalid option or argument: " "${1}" >&2
_usage
exit 1
;;
esac
done

#### Check if all required options are provided
if [[ -z "${copyfrom}" || -z "${creation}" || -z "${varnum}" || -z "${step}"
]]; then
_usage
exit 1
fi

#### Print the parsed options
echo "copy-from=$copyfrom, creation=$creation, var-num=$varnum, step=$step"

&#x200B;

https://redd.it/155magg
@r_bash