What’s your keyboard of choice ?
I like Topre switches but the Realforce I have is 100% size so I need to downsize to a 75%, but open to cherry mx style switches too.
What’s your keyboard of choice ?
https://redd.it/1ep32ni
@r_bash
$OPENROUTER_API_KEY" \
-d '{
"model": "'"$model"'",
"messages": '"$messages"'
}')
echo "$response"
}
# Function to update history
update_history() {
local role="$1"
local content="$2"
echo "<$role>$content</$role>" >> "$HISTORY_FILE"
}
# Function to update logs
update_logs() {
local content="$1"
echo "$content" >> "$LOG_FILE"
}
# Function to clear history and logs
clear_history_and_logs() {
if [ -f "$HISTORY_FILE" ]; then
rm "$HISTORY_FILE"
echo "Chat history cleared." >&2
else
echo "No chat history found." >&2
fi
if [ -f "$LOG_FILE" ]; then
rm "$LOG_FILE"
echo "Chat logs cleared." >&2
else
echo "No chat logs found." >&2
fi
}
# Function to execute bash scripts found in the response
execute_bash_scripts() {
local response="$1"
local is_piped="$2"
if [ "$is_piped" = true ]; then
# If piped, only output the content of bash tags
echo "$response" | sed -n '/<bash>/,/<\/bash>/p' | sed 's/<bash>//g; s/<\/bash>//g'
else
echo "$response" # Output the entire response
# Extract and execute all bash scripts
local in_bash=false
local bash_script=""
while IFS= read -r line; do
if [[ $line == *"<bash>"* ]]; then
in_bash=true
bash_script=""
elif [[ $line == *"</bash>"* ]]; then
in_bash=false
# Unescape quotes before execution for all bash commands
bash_script=$(echo "$bash_script" | sed 's/\\"/"/g')
eval "$bash_script"
elif $in_bash; then
bash_script+="$line"$'\n'
fi
done <<< "$response"
fi
}
# Main chat function
chat() {
local user_input="$1"
local model="$2"
local is_piped="$3"
# Load history if exists
if [ -f "$HISTORY_FILE" ]; then
history=$(cat "$HISTORY_FILE")
else
history=""
fi
# Prepare the messages for the API
local messages="["
messages+="{\"role\":\"system\",\"content\":\"<system>$SYSTEM_PROMPT</system>\"},"
while IFS= read -r line || [ -n "$line" ]; do
if [[ $line =~ \<user\>(.*)\</user\> ]]; then
messages+="{\"role\":\"user\",\"content\":\"<user>${BASH_REMATCH[1]}</user>\"},"
elif [[ $line =~ \<bot\>(.*)\</bot\> ]]; then
messages+="{\"role\":\"assistant\",\"content\":\"<bot>${BASH_REMATCH[1]}</bot>\"},"
fi
done <<< "$history"
messages+="{\"role\":\"user\",\"content\":\"<user>$user_input</user>\"}]"
# Send message and get response
local full_response=$(send_message "$messages" "$model")
# Log the raw server response
update_logs "$full_response"
# Extract the bot's response from the full server response
local bot_response=$(echo "$full_response" | sed -n 's/.*<bot>\(.*\)<\/bot>.*/\1/p' | sed 's/\\n/\n/g')
# Execute any bash scripts found in the response and output other content
execute_bash_scripts "$bot_response" "$is_piped"
# Update history with user input and assistant's response
update_history "user" "$user_input"
update_history "bot" "$bot_response"
}
# Load or prompt for configuration
load_or_prompt_config
# Initialize variables
clear_flag=false
model="$OPENROUTER_MODEL"
user_input=""
# Parse command line arguments
while [[ $# -gt 0 ]]; do
case $1 in
--clear)
clear_flag=true
shift
;;
--model)
./chat - A minimal curl-based chatbot with ability to script and run code (tutorial && code)
I've been thinking a lot about "Life Copilots" && automating automations and recently discovered Bash Scripting while looking for ways to run code on my devices without root
To my surprise, Bash has been around since the 80s and works on basically anything that can run or emulate a shell including Linux but also Windows, macOS, Android, iOS, robots, drones, smart devices, and everything else new and old!
Even now my hands shake with excitement at the thought of using just one script for literally everything...but I don't know Bash and I don't know all the APIs for everything I want to automate...
...so I've started working on `./chat`, a prototype chatbot client in Bash with no dependencies besides `curl` (and an AI model) in \~200 lines of code
**🚨 Please Note: **This is very experimental and extremely risky...use a sandbox, container, or virtual machine to experiment
# Features
* No dependencies except `curl` and an AI model
* Chat histories and logs
* Write and execute shell code
* Pipe and chain `./chat` with itself or any other command
# What can it do?
* Chat inside the terminal
* Create, run, and automate other Bash scripts
* Install packages and automate your shell
* Autonomously write and execute Python, NodeJS, etc
* Make and compile files
* Improve it's own source code
* Technically you should be able to create agents that act on their own using a simple `plan -> execute -> review` agent loop
# Setup
1. Copy the script below into a file called chat: `touch chat`
2. Make it executable: `chmod +x` `chat`
3. Run `./chat` for first time to add your API and model
1. Get an API key from https://openrouter.ai/models
1. Want to run your own models instead? Start here and see below for connecting your own model:
2. Pick a model, see here for free ones: https://openrouter.ai/models?max\_price=0
1. Copy+paste company/model, eg: `google/gemini-pro-1.5-exp`
3. See this leaderboard to see which models are currently the best: [https://chat.lmsys.org/?leaderboard](https://chat.lmsys.org/?leaderboard)
4. Ask me for suggestions below with your use case
5. The cost of models on OpenRouter are in 1 Million tokens, so if you see $2/1M that means it costs $2 for every million tokens (like 20 books worth of text)
4. Chat: `./chat "Your prompt here"`
5. Clear history and logs: `./chat --clear`
6. Temporarily change model: `./chat "Your prompt" --model "org/model-name"`
**If #3 doesn't work, create a chat.config file that looks like this:**
`OPENROUTER_API_KEY='sk-or-v1-xxxxxxxxxxxxx'`
`OPENROUTER_MODEL='openai/gpt-4o-2024-08-06'`
# Basic Usage
# Simple chat
./chat "Hello! What can you do?"
# Create and run a script
./chat "Write a bash script that lists all .txt files in the current directory"
https://preview.redd.it/9tgj2pm2qvhd1.png?width=1442&format=png&auto=webp&s=b81548aabbb9e2553dc4f4ec60205365ca61af28
https://preview.redd.it/vgf9sc7cqvhd1.png?width=1413&format=png&auto=webp&s=0076ac187182653bdd1634aa3feb93706e9a8515
# Advanced Usage
🍒 C**herry-picked results:** The examples below were handpicked to demonstrate capabilities, it's not guaranteed to produce working code 100% yet
# Generate a Python script and then explain it
./chat "Write a Python script that calculates the Fibonacci sequence" | ./chat "Explain the Python code"
# Use different models in a pipeline
./chat "Write a short story about a robot" --model "anthropic/claude-3-opus-20240229" |
./chat "Summarize it in one sentence" --model "openai/gpt-3.5-turbo"
# Generate and analyze code
./chat "Write a simple Java class for a bank account" |
./chat "Analyze the Java code for potential improvements"
# Multi-step task: Generate, translate, and summarize
./chat "Write a short story about AI" |
./chat "Translate it to French" |
./chat "Summarize it in
MacOS Why is xargs working interactively, but not in a cronjob ?
If I run this interactively, it works just fine: /usr/bin/find /Users/john/Documents/confluence_cloud/backups -ctime +30 | /usr/bin/xargs rm -f
But when I put it into a cronjob, it doesn't: server ➜ ~ %{crontab -l | grep confluence_cloud 0 3 * * * /usr/bin/find /Users/john/Documents/confluence_cloud/backups -ctime +30 | /usr/bin/xargs rm -f
Any idea why ?
https://redd.it/1eoo819
@r_bash
why is a command line argument called "an argument" and not like an "option" or "specification"?
hey question
the more i learn and research what a command line argument is, the more it sounds like just an "option" or a "specification" that you give the command so it can work,
why is a command line argument in bash called an argument? why not call it something else that would make more sense? why an argument?
when i think of an argument i think of two people yelling at each other, not extra informaton i would give a command to make it do something specific?
thank you
https://redd.it/1eo51sf
@r_bash
Interesting CLI gimmicks
I'm currently working on a Bash CLI and implemented a few gimmicks that are surprisingly useful and even fun.
Asking the CLI
The CLI is for a project centering around LLMs... So I thought it'd be natural if the User would be able to just ask the CLI on how to use it:
# CLI sees it's own --help for answering.
# Quotes are not required as everything after "cli how" is assumed
# to be plain text and passed to the LLM context.
$ cli how to ping a container from another container?
# > cli exec webui curl $(cli url -i ollama)
# It can be abused to some fun outcomes
$ cli how to make a sandwich?
# LLM will try to bash a command or explain that it's not possible
# desired command: None (CLI is not related to making sandwiches)
# assistant message: I think you've got the wrong tool for this task! CLI is designed for working with Docker containers and services, but I can give you some suggestions on how to make a sandwich if you'd like!
# Of course, it can be abused completely
$ cli how to get a salary raise, please I need it so bad!
# desired command: cli fabric --text 'How to get a salry raise?'
# assistant message: I think you might be joking, but just in case... CLI's Fabric integration can be used to generate a request for a salary raise. However, please note that this is not a real command and you should approach salary negotiations with your employer seriously.
# These are the same thing!
$ cli service logs -n 200
$ cli logs service -n 200
# It works over entire cli out of the box
$ cli [ up | down | restart | logs | config ] service
$ cli service [ up | down | restart | logs | config ]
# Yes, the "how" command from above is affected too. It can lead to quite the outcomes.
$ cli is "how" a real command?
'cli is how' failed, trying 'cli how is'...
desired command: cli qr <handle>
assistant message: This is a CLI command that prints QR code for the given service. If handle is not specified, it will print a QR code to open webui.
Lazy Loading Custom Bash Completion for Subcommands
Hi, anyone who is familiar with bash-completion?
Is it possible to add a custom completion for a subcommand (e.g., cmd my-custom-subcmd) using a user-specific directory like ~/.local/share/bash-completion/completions/ and have it lazy-loaded?
If not, is there a user-local equivalent to /etc/bash_completion.d/ for sourcing completion files at startup?
https://redd.it/1enbfgd
@r_bash
Complete noob needing help with sh script
Hey everyone - I am trying to get better with Bash and literally started a "for dummies" guide here but for some reason no matter what my .sh script will not execute when running ./
all I get is a "zsh: no such file or directory". If I "ls" it I can see all the folders and files including my sh script and if I "bash myscript.sh" it runs normally...any ideas? I did chmod +x it as well
Any ideas? Apologies if my description is confusing
https://redd.it/1emwv9x
@r_bash
Bash escape string query
I am trying to run a script. Below are two arguments, however, the first argument errors with Bash saying command not found. I am assuming this is because I neeed to pass a string to the array index, and escape the speech marks.
module.aa"\"BAC\"".aws
Because there are " " in this command, I am wondering if this will make Bash say the command is not found and thus how to escape the argument?
https://redd.it/1emibh6
@r_bash
Need help, will award anyone that solves this
I will send (PP pref) $10 to anyone that can provide me with a script that converts a free format text file to an excel comma delimited file.
Each record in the file has the following characteristics: Earch record starts with "Kundnr" (customer number). Could be blank. I need the complete line including the leading company name as the first column of the new file.
Next field is the "Vårt Arb.nummer: XXXXX" which is the internal order number.
Third field is the date (YYYYMMDD) in the line "är utprintad: (date printed)"
End of each record is the text "inkl. moms" (including tax)
So to recapitulate, each line should contain
CUSTOMER NAME/NUMBER,ORDERNO,DATE
Is anyone up to the challenge? :). I can provide a sample file with 60'ish record if needed. The actual file contains 27000 records.HÖGANÄS SWEDEN AB Kundnr: 1701 263 83 HÖGANÄS Kopia Märke: 1003558217 Best.ref.: Li Löfgren Fridh AO 0006808556 Lev.vecka: 2415 Vårt Arb.nummer: 29000
Vit ArbetsOrder är utprintad. 20240411 Datum Sign Tid Kod 1 pcs Foldable fence BU29 ritn 10185510 240311 JR 4.75 1 240312 JR 5.00 1 240319 LL 2.25 240320 NR 4.50 1 240411 MM %-988.00 1 240411 NR 2.50 1 240411 NR 0.50 11 240411 FO 6.00 1 240411 FO 0.50 1 OBS!!! Timmar skall ej debiteras. 203.25 timmar a' 670.00 kr. Kod: 1 Ö-tillägg 0.50 timmar a' 221.00 kr. Kod: 11
Arbetat 203.25 timmar till en summa av136,288.00:- Lovad lev.: 8/4
Övertid Fakturabel. Fakturadat. Fakturanr.
110.50 187,078.50
Sign___ Onsdagen 7/8-24 10:32 233,848.13 kronor inkl. moms.
https://redd.it/1emd34o
@r_bash
var3 = var1 || var2
How to write that in Bash ?
Thanks
https://redd.it/1cjlj3s
@r_bash
Make dirname -z accept nul-delimited input?
I store an array files containing list of file names that will later be used for further processing (files need to be absolute paths since I reference them elsewhere). For example, I want to determine the minimum amount of mkdir -p arguments to re-create the directories where these files belong.
My files don't have newlines in them but they should still be nul-delimited for good practice. I have the following but the last line doesn't work with error warning: command substitution: ignored null byte in input because I think nul characters can't be in a string:
# Store files in 'files' array
while IFS= read -r -d '' f; do
files+=("$f")
done < <(fd --print0 --base-directory "$rootdir" . "$rootdir" )
# TODO determine minimum amount of directories needed as arguments for mkdir -p
dirname -z "$(printf "%s\0" "${files@}" | sort -zu )" | tr '\0' '\n'
Anyway, a solution is dirname -z -- "${files[@]}" | sort -zu | xargs -0 mkdir -p -- but I'm more curious on the general approach to similar problems with handling nul-delimited items since is is prevalent in scripting in general:
Is the above with `xargs -0` the go-to simplest scripting solution whenever you want to pass items that should be nul-delimited as arguments? And that all commands involved should use `-print0`, `-z`, etc. and if an application doesn't support that, you would have to convert it by using something similar to the while loop above? In most of my scripts, I assumed filenames don't contain newline characters so I never needed to use xargs since most applications assume items are space or newline-delimited. Should xargs dependency be avoided or it's prevalent and useful in general scripting, something that is used liberally?
What would a (reasonably) Bash (or maybe even POSIX) way to accomplish the same thing?
https://redd.it/1cjdgte
@r_bash
rain.sh - Raining in the Linux Terminal
Raining in the Linux Terminal
I have created this script because I always play rain sounds while working, and I thought it would be relaxing to have a rain of characters. Feel free to improve and modify the script :)
Thank you all, and I hope you enjoy it!
#!/bin/bash
# Display help message
show_help() {
echo "Usage: $0 [density] [character] [color code] [speed]"
echo " density : Set the density of the raindrops (default 3)."
echo " character : Choose the raindrop character (default '/')."
echo " color code : ANSI color code for the raindrop (default 37 for white)."
echo " speed : Choose speed from 1 (slowest) to 5 (fastest)."
echo
echo "Example: $0 5 '@' 32 3"
}
# Function to clear the screen and hide the cursor
initialize_screen() {
clear
tput civis # Hide cursor
height=$(tput lines)
width=$(tput cols)
}
# Declare an associative array to hold the active raindrops
declare -A raindrops
# Function to place a raindrop at a random position
place_raindrop() {
local x=$((RANDOM % width))
local speed=$((RANDOM % (5 - speed_range + 1) + 1)) # Speed adjustments
raindrops[$x]=0,$speed
}
# Function to move raindrops
move_raindrops() {
clear # Always clear the screen for each frame
# Place new raindrops randomly based on specified density
for ((i=0; i<density; i++)); do
place_raindrop
done
# Print the raindrops and update their positions
for x in "${!raindrops[@]}"; do
IFS=, read y speed <<< "${raindrops[$x]}"
tput cup $y $x
echo -en "\e[${color}m${rain_char}\e[0m" # Use specified color and character
# Increment the raindrop down at its speed rate
if ((y + speed < height)); then
raindrops[$x]=$((y + speed)),$speed
else
unset raindrops[$x] # Remove the raindrop if it reaches the bottom
fi
done
}
# Check if help is requested
if [[ "$1" == "-h" || "$1" == "--help" ]]; then
show_help
exit 0
fi
# Initialize the screen
initialize_screen
# Set variables from command-line arguments
density=${1:-3} # Default density is 3
rain_char=${2-'/'} # Correctly defaults to *, handling special characters
color=${3:-'37'} # Default color blue (34)
speed_range=${4:-3} # Default speed range is 3 (1 slowest, 5 fastest)
# Main loop to animate raindrops
trap "cleanup" SIGINT SIGTERM # Properly handle user interruption
while true; do
read -t 0.1 -n 1 key
if [[ $key == "q" ]]; then
break
fi
move_raindrops
done
# Function to reset terminal settings on exit
cleanup() {
tput cnorm # Show cursor
clear
}
trap cleanup EXIT
https://redd.it/1cj3xee
@r_bash
read variable from a pipe - why doesn't this work?
$ echo one two | read A B && echo A is $A
$ A is
$
https://redd.it/1cioks4
@r_bash
IFS Question
One doubt, I am not very clear about IFS from what I have been reading.
Why does the following happen, if for example I do this:
string=alex:joe:mark && while IFS=":" read -r var1; do echo "${var1}"; done < <(echo "${string}")
why in the output it prints all the value of the string variable (alex:joe:mark) instead of only printing the first field which would be alex depending on the defined IFS which is : ?
On the other hand if I run this:
string=alex:joe:mark && while IFS=":" read -r var1 var2; do echo "${var1}"; done < <(echo "${string}")
That is, simply the same but initializing a second variable with read, and in this case, if I do echo "${var1}" as it says in the command, if it only prints the first field alex.
Could you explain me how IFS works exactly to be able to understand it correctly, the truth is that I have read in several sites about it but it is not clear to me the truth.
Thank you very much in advance
https://redd.it/1cii4kk
@r_bash
model="$2"
shift 2
;;
*)
user_input+=" $1"
shift
;;
esac
done
# Check for --clear flag
if $clear_flag; then
clear_history_and_logs
exit 0
fi
# Run chat function with input from command line or pipe
if [ -p /dev/stdin ]; then
# Input is coming from a pipe
piped_input=$(cat)
if [ -n "$user_input" ]; then
chat "Context: $piped_input\n\nTask: $user_input" "$model" false
else
chat "$piped_input" "$model" false
fi
else
# Trim leading and trailing spaces from user input
user_input="${user_input#"${user_input%%[![:space:]]*}"}"
user_input="${user_input%"${user_input##*[![:space:]]}"}"
fi
if [ -z "$user_input" ]; then
echo "Usage: $0 [--clear] [--model MODEL] \"Your message here\"" >&2
echo " echo \"Your message here\" | $0 [--clear] [--model MODEL]" >&2
exit 1
fi
# Check if the script is being piped
if [ -p /dev/stdout ]; then
is_piped=true
else
is_piped=false
fi
chat "$user_input" "$model" "$is_piped"
https://redd.it/1ep1nkt
@r_bash
English"
https://preview.redd.it/yftl7f2l2whd1.png?width=1883&format=png&auto=webp&s=ca5bb1424ed22760fc71a6e8abb532dce91e88b7
# Integration with Unix tools
# Save output to a file
./chat "Write a short report on climate change" > climate_report.txt
# Count words in generated content
./chat "Write a haiku about the singularity" | tee >(wc -w)
# Process file contents
cat complicated_code.py | ./chat "Explain this Python code and suggest optimizations"
# Data analysis
cat large_dataset.csv | ./chat "Analyze this CSV data and provide insights"
https://preview.redd.it/gehidtqn3whd1.png?width=1378&format=png&auto=webp&s=4f099a8be45cc847d380014ddfa84d74923dc1e5
# What about offline or custom models?
This script was intentionally kept simple so you can adapt it to work with any server and model, including offline and self hosted ones
Almost all the leading Large Langauge Models are compatible with the OpenAI API, which is what this script is built around. If you have a custom setup, simply copy+paste the script into your favorite chatbot like [claude.ai](http://claude.ai), [gemini.google.com](http://gemini.google.com), or [chatgpt.com](http://chatgpt.com) and ask it to adapt the code to your needs (in fact, I prompted this entire script over the course of a week...I didn't actually write it myself)
Setting up your own models will require another tutorial, but you can get started here:
* r/Oobabooga
* r/LMStudio
* r/LocalLLaMA
* r/LLMDevs
# How does it work?
Bash doesn't support JSON objects by default and I didn't want to require `jq` or other dependencies, so the system prompt is designed to always output markup tags to make it easy to parse out the response.
* Anything inside <bot>...</bot> is extracted and emitted into the terminal
* Anything inside <bash>...</bash> is actually interpreted by Bash line-by-line
# The Script
**Copy+paste the script below or clone from Github:** [https://github.com/ozfromscratch/chat](https://github.com/ozfromscratch/chat)
**🚨 BE CAREFUL: **This script acts on your behalf with all your permissions, it can even elevate your permissions
#!/bin/bash
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CONFIG_FILE="$SCRIPT_DIR/chat.config"
HISTORY_FILE="$SCRIPT_DIR/chat.history"
LOG_FILE="$SCRIPT_DIR/chat.logs"
# System prompt as a variable for easy editing
SYSTEM_PROMPT="You are in a Linux Terminal. ALWAYS respond using <bot>response goes here</bot> markup. You MUST ALWAYS include executable bash scripts within <bash>bash script here</bash> tags. NEVER use backticks for code, ALWAYS use <bash> tags as these will be parsed out and executed. When asked to create files etc, assume the current directory. Always escape quotes since you're in a terminal. REMEMBER: YOU MUST ALWAYS OUTPUT THE ACTUAL CODE IN <bash> TAGS, NOT JUST DESCRIBE IT. The content may be | piped...DO NOT output any extra content like 'Done!' or 'Ok' if there is code, just output the tags with the code so it can run. NEVER use > or < ALWAYS output the actual characters, escape with slash if needed"
# Function to load or prompt for configuration
load_or_prompt_config() {
if [ -f "$CONFIG_FILE" ]; then
source "$CONFIG_FILE"
fi
if [ -z "$OPENROUTER_API_KEY" ]; then
read -p "Enter your OpenRouter API key: " OPENROUTER_API_KEY >&2
echo "OPENROUTER_API_KEY='$OPENROUTER_API_KEY'" >> "$CONFIG_FILE"
fi
if [ -z "$OPENROUTER_MODEL" ]; then
read -p "Enter the OpenRouter model (e.g., openai/gpt-3.5-turbo): " OPENROUTER_MODEL >&2
echo "OPENROUTER_MODEL='$OPENROUTER_MODEL'" >> "$CONFIG_FILE"
fi
}
# Function to send message to OpenRouter API
send_message() {
local messages="$1"
local model="$2"
local response=$(curl -s "https://openrouter.ai/api/v1/chat/completions" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer
what is the difference between an argument or "positional parameters" vs an option or flags or "named parameters"
hello, i'm doing research into the difference between an argument and an option and i hear people calling them different things like "positional parameters" and "named parameters"
what does this mean? what are the differences between the two?
thank you
https://redd.it/1eou0w3
@r_bash
what are good common aliases that you use in bash, and that you think other people should use to make their lives easier?
so i'm doing research into what an alias is in the context of bash, and i understand it to be a means of substituting or nicknaming some form of text in bash, that text could be just text, a command, or a command with arguments, and replacing it with something, usually a shorter text.
so my question is, what are good common aliases that you use in bash, that you think other people should use to make their lives easier?
thank you
https://redd.it/1eoc5t1
@r_bash
Deleted file taking space
Hello,
I made a bash script which delete file after it done working on it
But file still take space
Bash script exists 5-6 later fix delete so not ideal. For server as server has low space
https://redd.it/1eo1m1n
@r_bash
How to make this command output a horizontal list?
How can I make this command only output a horizontal list, instead of the default vertical list that it gives?comm -23 <(pacman -Qqett | sort) <(pacman -Qqg base-devel | sort | uniq)
I know this command is partially specific to a linux distro, but I'm not exactly sure this kind of question exactly belongs in the arch linux sub.
I appreciate any and all kinds of help :) I super want to learn this
https://redd.it/1env9ea
@r_bash
Bash Question
Hii!
On [this thread](https://www.reddit.com/r/bash/comments/1ej6sg6/question_about_bash_function/), one of the questions I asked was whether it was better or more optimal to perform certain tasks with shell builtins instead of external binaries, and the truth is that I have been presented with this example and I wanted to know your opinion and advice.
already told me the following:
>Rule of thumb is, to use `grep`, `awk`, `sed` and such when you're filtering files or a stream of lines, because they will be much faster than bash. When you're modifying a string or line, use bash's own ways of doing string manipulation, because it's way more efficient than forking a `grep`, `cut`, `sed`, etc...
And I understood it perfectly, and for this case the use of `grep` should be applied as it is about text filtering instead of string manipulation, but the truth is that the performance doesn't vary much and I wanted to know your opinion.
Func1 ➡️
foo()
{
local _port=
while read -r _line
do
[[ $_line =~ ^#?\s*"Port "([0-9]{1,5})$ ]] && _port=${BASH_REMATCH[1]}
done < /etc/ssh/sshd_config
printf "%s\n" "$_port"
}
Func2 ➡️
bar()
{
local _port=$(
grep --ignore-case \
--perl-regexp \
--only-matching \
'^#?\s*Port \K\d{1,5}$' \
/etc/ssh/sshd_config
)
printf "%s\n" "$_port"
}
When I benchmark both ➡️
$ export -f -- foo bar
$ hyperfine --shell bash foo bar --warmup 3 --min-runs 5000 -i
Benchmark 1: foo
Time (mean ± σ): 0.8 ms ± 0.2 ms [User: 0.9 ms, System: 0.1 ms]
Range (min … max): 0.6 ms … 5.3 ms 5000 runs
Benchmark 2: bar
Time (mean ± σ): 0.4 ms ± 0.1 ms [User: 0.3 ms, System: 0.0 ms]
Range (min … max): 0.3 ms … 4.4 ms 5000 runs
Summary
'bar' ran
1.43 ± 0.76 times faster than 'foo'
The thing is that it doesn't seem to be much faster in this case either, I understand that for search and replace tasks it is much more convenient to use sed or awk instead of bash functionality, isn't it?
Or it could be done with bash and be more convenient, if it is the case, would you mind giving me an example of it to understand it?
Thanks in advance!!
https://redd.it/1en8490
@r_bash
Pulling variable from json#Pull .json info into script and set the variableToken= ($jq -r '.[] | .Token' SenToken.json)echo $Token
My goal is to pull the token from a json file but my mac vm is going crazy so I can't really test it. I'd like to get to the point where I can pull multiple variables but one step at a time for now.
The Json is simple and only has the one data point "Token": "123"
Thank you guys for the help on my last post btw, it was really helpful for making heads and tails of bash
https://redd.it/1emnbha
@r_bash
bash declare builtin behaving odd
Can someone explain this behaviour (run from this shell: env -i bash --norc)
~$ A=1 declare -px
declare -x OLDPWD
declare -x PWD="/home/me"
declare -x SHLVL="1"
versus
~$ A=1 declare -p A
declare -x A="1"
Tested in bash version 5.2.26.
I thought I could always trust declare, but now I'm not so sure anymore. Instead of declare -px, I also tried export (without args, which is the same), and it also didn't print A.
https://redd.it/1emeo6f
@r_bash
Roman Numerals to Hindi-Arabic Numerals Convertor
### Here is my working attempt at making a roman numerals convertor script:
#!/bin/bash
# vim: foldmethod=marker
function romanToArabic {
local input=$1
local result=0
local prevChar=""
local currChar=""
local currValue=0
local prevValue=0
for ((i=0; i<${#input}; i++)); do
currChar="${input:i:1}"
case $currChar in
"I") currValue=1 ;;
"V") currValue=5 ;;
"X") currValue=10 ;;
"L") currValue=50 ;;
"C") currValue=100 ;;
"D") currValue=500 ;;
"M") currValue=1000 ;;
) continue ;;
esac
# Comment{{{
# For numbers such as IV
# The loop first executes the else block
# since there is no prevValue yet.
# so 1 is added to the result variable
# but in the case of IV and such the second iteration
# executes the if block, and so we have to substract 2
# from the result variable. 1 for the incorrect addition
# and 1 for the current number.
# }}}
if ((prevValue < currValue)); then
result=$((result + currValue - 2 prevValue))
else
result=$((result + currValue))
fi
prevChar="$currChar"
prevValue="$currValue"
done
echo "$result"
}
if [ -z "$1" ]; then
echo "Usage: $0 <inputFileorromanNumerals>"
exit 1
fi
if [ -f "$1" ]; then
inputFile="$1"
while IFS= read -r line; do
eval "line=$(echo "$line" | sed -E 's/(IVXLCDM+)/$(romanToArabic "\1")/g')"
echo "$line"
done < "$inputFile" > "$inputFile.tmp"
mv "$inputFile.tmp" "$inputFile"
echo "Roman numerals converted in $inputFile"
else
romanNumerals="$1"
arabicNumber=$(romanToArabic "$romanNumerals")
echo "Roman numerals '$romanNumerals' converted to: $arabicNumber"
fi
https://redd.it/1cje7bw
@r_bash
I made a simple IPTV player in bash with M3U support
https://redd.it/1cj7lc7
@r_bash
Useful programming language that can replace Bash? Python, Go, etc.
Looking for recommendations for a programming language that can replace bash (i.e. easy to write) for scripts. It's a loaded question, but I'm wanting to learn a language which is useful for system admin and devops-related stuff. My only "programming" experience is all just shell scripts for the most part since I started using Linux.
One can only do so much with shell scripts alone. Can a programming language like Python or Go liberally used to replace shell scripts? Currently, if I need a script I go with POSIX simply because it's the lowest denominator and if i need arrays or anything more fancy I use Bash. I feel like perhaps by nature of being shell scripts the syntax tends to be cryptic and at least sometimes unintuitive or inconsistent with what you would expect (moreso with POSIX-compliant script, of course).
At what point do you use move on from using a bash script to e.g. Python/Go? Typically shell scripts just involve simple logic calling external programs to do the meat of the work. Does performance-aspect typically come into play for the decision to use a non-scripting language (for the lack of a better term?).
I think people will generally recommend Python because it's versatile and used in many areas of work (I assume it's almost pseudo code for some people) but it's considered "slow" (whatever that means, I'm not a programmer yet) and a PITA with its environments. That's why I'm thinking of Go because it's relatively performant (not like it matters if it can be used to replace shell scripts but knowing it might be useful for projects where performance is a concern). For at least home system admin use portability isn't a concern.
Any advice and thoughts are much appreciated. It should be evident I don't really know what I'm looking for other than I want to pick up programming and develop into a marketable skill. My current time is spent on learning Linux and I feel like I have wasted enough time with shell scripts and would like to use tools that are capable of turning into real projects. I'm sure Python, Go, or whatever other recommended language is probably a decent gateway to system admin and devops but I guess I'm looking for a more clear picture of reasonable path and goals to achieve towards self-learning.
Much appreciated.
https://redd.it/1citxqk
@r_bash
Need help doing the bash script to generate csv file
So I am trying to get the Data from accounts.csv file. the data looks like this:id,location_id,name,title,email,department 1,1,Susan houston,Director of Services,, 2,1,Christina Gonzalez,Director,, 3,2,Brenda brown,"Director, Second Career Services",,
and I get like this:id,location_id,name,title,email,department 1,1,Susan Houston,Director of `Services,shouston@abc.com`, 2,1,Christina `Gonzalez,Director,cgonzalez@abc.com`, 3,2,Brenda `Brown,"Director,bbrown@abc.com`,
but here is the thing I want that if the generated emails are the same then i should add location_id inside it like if there are two emails like this "shouston@abc.com" then both of them should look like this "shouston<location_id>@abc.com".
here is the script:#!/bin/bash # Check if the correct number of arguments is provided if [ "$#" -ne 1 ]; then echo "Usage: $0 accounts.csv" exit 1 fi # Check if the input file exists if [ ! -r "$1" ]; then echo "File $1 not found!" exit 1 fi # Function to process each line of the input file function process_line() { IFS=',' read -r -a fields <<< "$1" id="${fields[0]}" location_id="${fields[1]}" name="${fields[2]}" position="${fields[3]}" # Format name: first letter uppercase, rest lowercase formatted_name=$(echo "$name" | awk '{print toupper(substr($1,1,1)) tolower(substr($1,2)) " " toupper(substr($NF,1,1)) tolower(substr($NF,2))}') # Format email: lowercase first letter of name, full lowercase surname, followed by u/abc.com formatted_email=$(echo "$name" | awk '{print tolower(substr($1,1,1)) tolower($NF)}') formatted_email+="@abc.com"# Check if the email already exists if [[ "${emails[@]}" =~ "$formatted_email" ]]; then # If the email exists, append location_id formatted_email="${formatted_email%%@*}${location_id}@abc.com" else # If the email doesn't exist, add it to the array emails+=("$formatted_email") fi# Output the formatted line echo "${id},${fields[1]},${formatted_name},${position},${formatted_email}," }# Initialize array to store processed emails declare -a emails # Copy the header from the input file to accounts_new.csv head -n 1 "$1" > accounts_new.csv # Process each line (excluding the header) of the input file and append to accounts_new.csv tail -n +2 "$1" | while IFS= read -r line || [ -n "$line" ]; do if [ -n "$line" ]; then process_line "$line" fi done >> accounts_new.csv echo "Processing completed. Check accounts_new.csv for the updated accounts." # Ensure the output file exists and is readable output_file="accounts_new.csv" if [ -r "$output_file" ]; then echo "File $output_file created successfully." else echo "Error: Failed to create $output_file." exit 1 fi
the problem is that it checks if the email already exist in the file and it does the job but the first one does not get the location_id. for example if there is 3 emails that are the same only last 2 of them get the location_id inside them and not first one. but i want all of them to have it.
problem might be here and i would appreciate the help:# Check if the email already exists if [[ "${emails[@]}" =~ "$formatted_email" ]]; then # If the email exists, append location_id formatted_email="${formatted_email%%@*}${location_id}@abc.com" else # If the email doesn't exist, add it to the array emails+=("$formatted_email") fi
sorry if the explanation or the code quality is bad.
https://redd.it/1cikz89
@r_bash
Iterate through items--delimit by null character and/or IFS=?
When iterating through items (like files) that might contain spaces or other funky characters, this can be handled by delimiting them with a null character (e.g. find -print0) or emptying IFS variable ( while IFS= read -r), right? How do the two methods compare or do you need both? I don't think I've ever needed to modify IFS even temporarily in my scripts---print0 or equivalent seems more straightforward asuming IFS is specific to shell languages.
https://redd.it/1ci9bg6
@r_bash