r_bash – Telegram
"${requiredPackages[@]}"; do
# :
# done
###############################################################################################################
# TODO: Should we use a named pipe for communication with subprocess instead ???
###############################################################################################################
# Would have to re-do a lot of logic for this route.
# if [ ! -p "${namedPipe}" ]; then
# mkfifo -m "a=rw" "${namedPipe}" #Man page literally says "not a=rw", but what does that mean?
# fi
###############################################################################################################
# TODO: Use array of URL's for tracking multiple websites.
###############################################################################################################
# Don't actually need this at all right now, but maybe one day...
###############################################################################################################

#Does not try to handle race-conditions, but I don't think it should not be a problem.
declare -A globalState;

function setGlobalState()
{
local -r varName="${1}"
local -r varValue="${2}"

if [ ${#} -eq 2 ]; then
globalState["${varName}"]="${varValue}"
fi

printf "# Using associative array for easy addition of new variables\n" | sudo tee "${sharedMemory}" > /dev/null
declare -p globalState | sudo tee -a "${sharedMemory}" > /dev/null
}

function getGlobalState()
{
local -r varName="${1}"
local -r varType="${2}"
local success=true
if [ -f "${sharedMemory}" ]; then
source "${sharedMemory}"
if [ ${#} -ge 1 ]; then
if [[ "${globalState[${varName}]}" != "" ]]; then
printf "%s" "${globalState[${varName}]}"
else
success=false
fi
fi
else
success=false
fi

if ! ${success}; then
if [[ ${varType} == "bool" ]]; then
printf "false";
elif [[ ${varType} == "int" ]]; then
printf "0";
elif [[ ${varType} == "string" ]]; then
printf "";
fi
return 1
fi
return 0
}


function cleanupSharedMemory()
{
if [ -f "${sharedMemory}" ]; then
sudo rm -vf "${sharedMemory}"
fi
}

setGlobalState "ring" "false"

dateFmt="+%Y.%m.%d_%I:%M%P"
#dateFmt="+%Y-%m-%d_%H:%M:%S.%3N"
function getDateTimeStamp()
{
date "${dateFmt}"
}

function getLogSize()
{
wc -c "${logFile}" | cut -f 1 -d ' '
}

function getLogLength()
{
wc -l "${logFile}" | cut -f 1 -d ' '
}

function log()
{
local -r extFmt="${1}"
printf "%s | ${extFmt}\n" "$(getDateTimeStamp)" "${@:2}" | tee -a "${logFile}"
}

function truncateLog()
{
local -r percentToKeep="${1}"

local -r logSize="$(getLogSize)"
local -r numLinesStart="$(getLogLength)"
# shellcheck disable=SC2155 # Masking return values by declaring and assigning together.
local numLines="$(echo "scale=0; ${numLinesStart} * ${percentToKeep}" | bc)"
numLines="${numLines%.*}" #Round down to nearest int.

# shellcheck disable=SC2005 # It's not a useless echo! It's not! I love echo...
echo "$(tail "-${numLines}" "${logFile}" 2> /dev/null)" > "${logFile}"

log "Trimmed output size: %b -> %b" "${logSize}" "$(getLogSize)"
log "Trimmed output size: %b -> %b" "${numLinesStart}" "$(getLogLength)"
}

printf -v dividerVar "<%.0s>%.0s" {1..80}
function divider()
{
printf "%b\n" "${dividerVar}">> "${logFile}"
}



function ringer()
{
local -r startVolume=$(amixer get Master | grep -o "[0-9]*%" | head -1) #Record current volume level
# shellcheck disable=SC2034 # The variable ${uid} is used when testing as cron job.
local -r uid=$(id -u "${user}")
local ring=true #Should always be true fist call.
if [[ "$(getGlobalState "ring")" != "${ring}" ]]; then
printf "Ringer was called with incorrect ring state! Check logical flow!\n"
fi

while ${ring}; do
amixer set Master 20% > /dev/null #I use headphones, and I don't want to blast out my eardrums

# Ok, weird one. Audio will not play over
same device user is using, so we need to specify a different one.
# So, if user is using laptop speakers, we can play though properly equipped external HDMI montior.
# Also, the audio is muted for the first second of play, so we will play the sound twice, but hear it once.
sudo -H -i -u "${user}" "aplay" -D "${audioOutputDevice}" "${notificationSound}" "${notificationSound}"

# This version works if run by user directly (i.e. Not as cron job)
# aplay -D "${audioOutputDevice}" "${notificationSound}" "${notificationSound}" > /dev/null

amixer set Master "${startVolume}" > /dev/null #Reset volume to what it was before
sleep 1
ring=$(getGlobalState "ring" "bool")
done
setGlobalState "ring" "false"
}

function popup()
{
local -r website="${1}"
local -r width=400
local -r height=200
local -r noscript="${notificatonTitle}"
local -r message="${notificatonMsg}\n${1}\nThis dialoge was created by: $(realpath "${BASH_SOURCE[0]}")"

zenity \
--warning \
--text="${message}" \
--noscript="${noscript}" \
--width="${width}" \
--height="${height}"
}

function checkReDirect()
{
local -r lastRedirect="$( < "${lastRedirectFile}" )"
local currentRedirect=""

currentRedirect="$(curl -ILs -o /dev/null -w "%{url_effective}" "${urlToWatch}")"
curlCode="${?}"
if [ "${curlCode}" -ne 0 ]; then
if [[ "${ERROR_SOURCED}" == "true" ]]; then
log "$(checkError "curl" "${curlCode}")"
else
log "Error! curl failed with ${curlCode}"
fi
return
elif [[ "${currentRedirect}" == "${lastRedirect}" ]]; then
log "Executing: %b ( No news... )" "$(realpath "${BASH_SOURCE[0]}")"
return
else # This isn't needed since other cases do early return ...
log "Executing: %b ( NEWS!! )" "$(realpath "${BASH_SOURCE[0]}")"
listSubreddits
wget "${currentRedirect}" -O "${website}" # Grab page for analysis

redirectEnding=${lastRedirect%/} # Remove trailing slash if present
redirectEnding=${redirectEnding##*/} # Remove everything up to last slash (Shoud be left with last section of URL)

noscriptSuggestion="$(grep -o "<noscript>.*</noscript>" "${website}")" #TODO: Find better way to parse html
noscriptSuggestion="${noscriptSuggestion#*>}" # Strip off <noscript>
noscriptSuggestion="${noscriptSuggestion%<*}" # Strip off </noscript>
log "Title Suggestion: ${redirectEnding} - ${noscriptSuggestion}"

log "Opening %s\n" "${currentRedirect}"
printf "%s" "${currentRedirect}" > "${lastRedirectFile}"


setGlobalState "ring" "true"
ringer & # Non-blocking so it will keep ringing until killed.
ringerPID=${!} # Keep this as global variable.

#Attempt to open URL in default web-broswer
if command -v gnome-open > /dev/null; then
gnome-open "${currentRedirect}" &
[ -f "${subredditList}" ] && [ -s "${subredditList}" ] && gnome-open "${subredditList}" &
elif command -v xdg-open > /dev/null; then
xdg-open "${currentRedirect}" &
[ -f "${subredditList}" ] && [ -s "${subredditList}" ] && xdg-open "${subredditList}" &
elif command -v gio > /dev/null; then
gio open "${currentRedirect}" &
[ -f "${subredditList}" ] && [ -s "${subredditList}" ] && gio open "${subredditList}" &
fi

popup "${currentRedirect}" # Blocking command. Once popup is closed, we will kill the ringer.
setGlobalState "ring" "false" # Seems /dev/shm is the way to communicate with background processes.
printf "Popup closed. Waiting for ringer to end. [pid=%s]\n" "${ringerPID}"
wait "${ringerPID}"
printf "Ringer ended.\n"
fi
}

function listSubreddits()
{
# Maybe one of these subreddit will care about the URL change
if [ -f "${subredditsInput}" ]; then
# Expected format is simply to define an array named ${subreddits[@]}
# You can form that array however you want. Keep it simple, or go nuts.
source "${subredditsInput}"
fi

for subreddit in "${subreddits[@]%\/}"; do # Normalize sub names
by removing trailing slash if present.
subreddit="${subreddit##*\/}" # Normalize sub names by removing any subreddit prefix.
printf "https://old.reddit.com/r/%s\n" "${subreddit}"
done > "${subredditList}"
}


###############################################################################################################
############ Script Start #####################################################################################
###############################################################################################################

divider

# To list hourly noscripts that run.
# sudo run-parts --report --test /etc/cron.hourly
# If started as root, then re-start as "${user}": (https://askubuntu.com/a/1105580)
if [ "$(id -u)" -eq 0 ]; then
log "Refusing to run as root!"
#exit; #Don't run as root.
exec sudo -H -u "${user}" bash -c "${0}" "${@}" #Force run as user.
echo "This is never reached."
fi

# ${DISPLAY} is typically unset when root sudo's to user.
if [ -z "${DISPLAY+unset}" ]; then
export DISPLAY=":0.0"
fi

log "Running as \${USER}=${USER} id=$(id -u). Script version = ${version}"

function exitCron()
{
printf "Exiting due to interrupt\n" >> "${logFile}"
if [ -n "${ringerPID}" ] && ps -p "${ringerPID}" > /dev/null; then
kill -15 "${ringerPID}"
fi

# unset traps.
trap - SIGHUP
trap - SIGINT
trap - SIGQUIT
trap - SIGTERM

cleanupSharedMemory
exit 1
}

#Don't think this is nessesary, but just make sure we exit each process when told to.
trap exitCron SIGHUP SIGINT SIGQUIT SIGTERM

if [ ! -d "${workingDir}" ]; then
mkdir -p "${workingDir}"
fi

# For loop will excute once every 600 seconds (10 minutes) for an hour
# shellcheck disable=SC2034 # Not using variable ${i}
for i in {0..3599..600}; do
checkReDirect
#break; #Uncomment to run once for testing.
sleep 600;
done

logSize="$(getLogSize)"
#Trim log length by about 10% if we have gone over ${maxLogSize}.
if (( "${logSize}" > "${maxLogSize}" )); then
truncateLog "0.90"
fi

cleanupSharedMemory

###############################################################################################################
# References:
#
# Check if variable is empty or unset:
# https://stackoverflow.com/questions/3601515/how-to-check-if-a-variable-is-set-in-bash
# https://www.cyberciti.biz/faq/unix-linux-bash-noscript-check-if-variable-is-empty/
#
# Send variable to background process:
# https://stackoverflow.com/questions/13207292/bash-background-process-modify-global-variable
#
# Limit log size keeping last n lines:
# https://unix.stackexchange.com/questions/310860/how-do-you-keep-only-the-last-n-lines-of-a-log-file
#
###############################################################################################################

https://redd.it/z7endd
@r_bash
Press ctrl z and type bg from a bash noscript automatically

So i have a timer i run from telegram connected to my pc. Do anyone know if there is a possibility to automatically stop the noscript and ”automatically” put it under ”jobs” without ”&” when started.
Currently i have to manually press ctrl z and then type bg

https://redd.it/z7avv4
@r_bash
pass to xargs

Hello I'm trying to process the output of \
.

I run: mynoscript * to process all files in the current directory.

The output should be the full path of *.

This is what I have (not working):

echo ${@:1} | tr '\n' '\0' | xargs -0 -I "%" realpath "%"

can someone help?

https://redd.it/z7r0aj
@r_bash
How to make tests in .bashrc so they execute as fast as possible?

I am using this snippet from an AskUbuntu post in my own .bashrc, but would like to improve it so it works also in a tmux session:

if "$color_prompt" = yes ; then
# when system is accessed via SSH, hostname with light grey background
if [ $(pstree -s $$) = *sshd* ]; then sshbg="[\03348;5;7m\"; fi
# when used as root, change username to orange and '#' to red for prompt
if $(id -u) -eq 0 ; then usercol="[\03338;5;3m\"; hashcol="[\03338;5;1m\"; else usercol="[\03338;5;2m\"; fi
# bash PS1 prompt
PS1="${usercol}\u[$(tput sgr0)\]@[$(tput sgr0)\][\03338;5;4m\${sshbg}\h[$(tput sgr0)\]:[$(tput sgr0)\][\03338;5;6m\\w[$(tput sgr0)\]${hashcol}\\$ [$(tput sgr0)\]"
unset sshbg rootcol hashcol
fi

I can test similar to line 3 above if pstree -s $$ returns tmux: server, and if it does, I can test [[ $(pstree -s $(pgrep "tmux: client")) = *sshd* ]] to get the desired result.

So far, I have:

if "$color_prompt" = yes ; then
# when system is accessed via SSH, hostname with light grey background
if [ $(pstree -s $$) = *sshd* ]; then
sshbg="[\03348;5;7m\"
elif [ $(pstree -s $$) = *"tmux: server"* ]; then
if [ $(pstree -s $(pgrep "tmux: client")) = *sshd* ]; then
sshbg="[\03348;5;7m\"
fi
fi
# when used as root, change username to orange and '#' to red for prompt
...

Is there any better, especially faster way? Since it generates PS1, I would like it to be as fast as possible to not be annoying.

https://redd.it/z8033h
@r_bash
read command removes empty lines

#!/usr/bin/env bash
ls ??-??.json | while IFS= read -r line; do ./noscripts/add-missing-strings.js "$line"; done

What I have already tried:-played with ifs-read -r-started questioning if the problem is really here and not in the .js

All files - https://github.com/RDKRACZ/for-reddit/tree/main/noscripts

https://redd.it/z8955d
@r_bash
Is there any way to have a "longterm history" in addition to the normal history?

I like to keep a record of all the commands I have run on my VPS, because it's a good reference for how I installed or configured something many months ago. So I have my

HISTFILESIZE=10000, and HISTSIZE=10000

along with

export PROMPTCOMMAND="history -a; history -c; history -r;$PROMPTCOMMAND"

to keep the history file up to date after each command. But my command item numbers are in the 5000's now, so it's a little inconvenient to search through such a long history when I'm looking for something I just used a few days ago. Is there any way to to write to a file like .historylong in addition to my normal history? That way I could keep my normal history shorter and only reference the "indefinite history" when needed. And would there be any way to have .historylong displayed with a command line number that I could use in the infrequent times that I want to run something from long ago like:

!4573

https://redd.it/z8vubd
@r_bash
Why does sed delete the file's content when an output redirection is performed on the file, and not when using the append >> redirection?

For example, assume file.txt has the following content:

This is an example.

When I invoked the following command sed '/s/example/EXAMPLE/' file.txt > file.txt, the file's content was deleted.

But invoking this command sed '/s/example/EXAMPLE/' file.txt >> file.txt, produces the following output:

This is an example.
This is an EXAMPLE.

Isn't the output of sed produced on the stdout, and then the redirection operator redirects that output and rewrites the file?

https://redd.it/z8x9c8
@r_bash
Any way to keep the path context while running bash noscripts in other bash noscripts?

Im trying to make a noscript that will automate the process for running a server for a game "Unturned". My noscript only has this line of code:

su - steam -c "./Steam/steamapps/common/U3DS/ServerHelper.sh +LanServer/MyServer"

where it runs a file as the steam user in the steam user home directory, which inside that file, the last line runs:

./UnturnedHeadless.x8664 -batchmode -nographics "$@"

which SHOULD run the Unturned_Headless.x86_64 file, but doesnt, instead giving this error:

./Steam/steamapps/common/U3DS/ServerHelper.sh: line 18: ./UnturnedHeadless.x8664: No such file or directory

that file that its looking for being in the same folder as ServerHelper.sh . Im guessing that this is due it somehow not keeping the context of what dir its in while running the ServerHelper.sh file. Anyone know how i could fix it? (also, sorry if im making any dumb mistakes, ive never done any bash noscripting before)

https://redd.it/z8wzei
@r_bash
I'm trying to understand bash

How do i create magic file school.mgc that can be used with the command file to detect School

data files, and School data files always contain the string SCHOOL at offset 0

https://redd.it/z90nlo
@r_bash
DRY for this noscript?

My noscript feels pretty hideous for a lot of reasons. It seems like I should be storing the slack requests as vars but my attempts to do that were not working so I ended up with this functional but truly ugly noscript.

If you have any suggestions can you explain the how and the why? Def trying to develop better intuition about these things

&#x200B;

set -euo pipefail

if pgrep java; then

printf "App10 already running. Nothing more to do"
curl -X POST -H 'Content-type: application/json' --data '{
"attachments":
{
"text":"APP10 Java services already running. Nothing more to do",
"mrkdwn_in":["text",
"color":"#bfeff",
"noscript":"TeamCity App10 Action Report"
}
]}' https://hooks.slack.com/services/XXXX
else
sudo -i -u rlsmgr bash << EOF
echo "Starting APP10 Java Services"
echo "Verifying we are now rlsmgr"
whoami
source /home/rlsmgr/start-java.ksh
if pgrep java; then

printf "APP10 has been started and is now running."
curl -X POST -H 'Content-type: application/json' --data '{
"attachments":
{
"text":"APP10 has been started and is now running",
"mrkdwn_in":["text",
"color":"#bfeff",
"noscript":"TeamCity App10 Action Report"
}
]}' https://hooks.slack.com/services/XXX
else
printf "APP10 did not start."
curl -X POST -H 'Content-type: application/json' --data '{
"attachments":
{
"text":"APP10 did not start",
"mrkdwn_in":["text",
"color":"#bfeff",
"noscript":"TeamCity App10 Action Report"
}
]}' https://hooks.slack.com/services/XXXX
fi

EOF

fi

https://redd.it/z92cm4
@r_bash
output of arp -a to variable

Hi all!

I'm new to bash, am looking at tutorials but cant figure this specific one out.

What I am trying to do is write a noscript that can find my vacuum robots IP address. My plan is to use 'arp -a', look through the client names and then use the IP address of the client that matches the expected name. However, my first lines of code:

#!/bin/bash
client_list= $(arp -a)
echo "$client_list" #trying to get the full output of arp -a
for client in a
do
echo ">>> $client" # trying to get a single row from arp -a

yield me

line 2: <VACUUM_ROBOT_NAME>: command not found

So, the output of arp is properly being passed on to client_list and the first line is displayed, but it is then interpreted as a command? What am I doing wrong and how should I iterate through this list if not like this?

Thanks!

https://redd.it/z8vohf
@r_bash
best practises for organizing/refactoring noscript of thousand of lines

Hi everybody,

I question myself if there is a better way to organize my 3k lines noscript.

Actually it is organized as follow:

1. general constraints section
2. function section
3. main section

Main section itself contains a three sections menu for system config, docker containers config and experimental config (:D). The noscript it is used by me to easily reconfigure this or that on my debian based headless homeservers or vps.

Now, because of its length, it is going difficult to manage, if I need to add or modify a function I have to jump to the beginning and then return to the point where the add or the modify must be done.

An idea I have is to create different indipendent noscript for each function, but this have some side effects, the main is I have to jump from one file to another and this will happen very often because I include in the noscript all the bash codes I write for my lab (after some tests...) so I do not forget anything. Maybe this is a classic approach even if I have to rewrite the most of the noscript to replace functions with noscripts and related parameters; functions too should be redesigned a little bit, and I'll have to rethink a way of using global constraints

I also think I have to find a way to avoid that these noscripts may be directly executed, by mistake (by me, in the end :D), from the shell without be recalled from the "main", because otherwise I should rewrite them in a way they cannot damage files or folders etc.

I have other craxy ideas but before describing them and break my head on them I'm at a point where suggestions from experts are not only welcome but needed.

Hoping that I explain clearly, I look forward your messages!

https://redd.it/z95dch
@r_bash
How to make this one line .bat file into .sh file?

Hi folks.

Can someone please help me with this? I need this very simple .bat noscript to convert into .sh:

REM batch_audiowaveform.bat
for %%F in (*.flac) do audiowaveform -i "%%F" -o "%%~nF.json" -b 8 -z 128

How should this be written for .sh?

Thank you in advance!

https://redd.it/z9866r
@r_bash
How to repeat a command until it has a non-empty output

For example, if I want to scan my vm until it appears with something like...


sudo nping --tcp -p 22 -c 1 192.168.1.2 | grep "RCVD" | cut -d " " -f 4 | cut -d ":" -f 1

which pings once on the port and the grep and cuts just prunes everything except the host IP if indeed it responds to the ping.


How can I write this so that it will run my one liner until it produces anything other than an empty output, and then output that output normally for further noscripting?


Any help is appreciated, I've tried a fair bit of looking around, I feel like the test [\] feature or a "while true" loop might be useful in my solution, I'm just unsure of the test operators which isn't helped at all by the fact that I still quite haven't sorted out how to articulate this in a noscript quite yet as you can tell. TIA

https://redd.it/z980am
@r_bash
sshto

Tired of opening new sshto tabs for each host? It's not an issue anymore!)
Added two cool commands to sshto Add tabs and Ssh tabs for single host and group commands list.
The first one will add tab to your terminal running sshto with selected host. Or multiple tabs for all hosts in group.
The second one will add tab to your terminal running SSH session to selected host. Or multiple tabs for all hosts in group.

https://preview.redd.it/uei8wr87y83a1.png?width=680&format=png&auto=webp&s=3d8f62c3f86ebc001f7dbcfaab66819f95173f0e

Enjoy)

https://redd.it/z9invz
@r_bash
Message won't show

Hi I'm trying to learn how to assign a message to a variable, but I'm a little confused, I have this:

1 #!/usr/bin/env bash
2
3 ( -f first.txt && -f second.txt && rm first.txt &&
4 DELETE="File deleted") ||
5 DELETE="File not found"
6 echo "${DELETE}"

The second message works once first.txt has been deleted, but after creating another "first.txt" it checks it and deletes it, but no message shows and I can't work out why, I am expecting the message "File deleted", but I'm just getting a blank space instead. What do I have to do to get the first message to actually display?

for clarity the exercise it to set a message to a variable so that I can compile an email alert, doing echo "file deleted" instead of the attempted variable assignment works, but it is the variable assignment I am trying to learn.

https://redd.it/z9m9nq
@r_bash
Change specific line in a file

How do i change a specific line in a file with bash? i just have to set a false value to true in a file.

https://redd.it/z9s0b7
@r_bash
What is the best way to use the trap statement to run a command on ANY exit from the noscript no matter what the condition?

Basically I want to do this..

trap 'rm -r somefile' (what do I put here?)

I want the part between the single quotes to run no matter how the noscript exits... normal end, error in the noscript, control-C, some kind of internal error, whatever... I just want to make absolutely certain a file gets removed when the noscript ends. But I am so confused about what options I should use at the end. I see some places where people use "ERR EXIT" but others where it shows several numbers. I wish there were an "ANY REASON" option but if there is, I haven't stumbled across it yet. What should I be using here?

https://redd.it/z9y1cl
@r_bash