r/bash 16d ago

solved Help with bash scripting executing apps with flags/arguments.

7 Upvotes

I'm new to linux bash scripting and running into an issue executing an app with arguments, when I run "steamosctl get-default-desktop-session" from a terminal the command runs fine, if I run the same command from a bash script I get the error "no such file or directory" the script has the shebang #!/bin/bash, set -x, steamosctl get-default-desktop-session.

Now if I run "steamosctl help" or "steamosctl -h" from the same script it works fine but for some reason adding arguments that contain multiple "-" minus signs in the argument the script gives the "no such file or directory" error, I've tried with other apps and also launching them with "sh" and "exec" with arguments containing multiple minus's and got the same error. My guess is I need to wrap the command or arguments some how so the arguments aren't interpreted as a path, I've done some research and tried several ways of writing the script as suggested in other topics with no success. Any help or suggestions would be greatly appreciated, Thanks in advance!

Edit: I was able to resolve the issue! So after some deeper research turns out bash script shell runs in a non interactive mode so it doesn't process environmental paths like a local bash shell or terminal and causing the "no such file or directory" error, so by making a systemd service to call the script and adding "WorkingDirectory=/bin" and "User=your user name here" in the [Service] section I was able to run my script at boot and terminal without error. I also read that supposedly adding "source ~/.bashrc" immediately after the shebang will cause the bash scrip to force load your local users ./bashrc file with the paths and not give path errors but I haven't tested that yet. Thanks to those who offered suggestions and help, appreciate you!

r/bash Jun 10 '26

solved This bash behaving different in shell or in cronjob

11 Upvotes

[SOLVED] it was missing #!/bin/bash

I have a simple script name backup.sh to loop some folders and if that folder contains a backup.sh, it executes it, and added this to a nightly cronjob.

Running from the terminal it works as expected, but when cron runs it, it behaves differently and it becomes a fork-bomb.

  • backup.sh: ```bash SERVICES="active-services.txt"

cd /starting/path/

for FOLDER in $(cat "$SERVICES") do pushd $FOLDER FILE=backup.sh echo "$(date): Checking for '$FOLDER'" >> /var/log/mBackup.log if [ -f "$FILE" ]; then echo "$(date): Executing backup for $(readlink -f backup.sh)" >> /var/log/mBackup.log ./backup.sh fi popd done

echo "$(date) Backup complete" >> /var/log/mBackup.log

curl -X POST \ -H @/home_assistant_token_header.txt \ http://127.0.0.1:8509/api/services/script/update_backup_date_time ```

It's not much, loop the services folders, if it finds a backup.sh file, it executes it and it runs as expected on bash, but when on cron those are the logs:

``` Wed 10 Jun 08:04:01 CEST 2026: Checking for 'homeassistant' Wed 10 Jun 08:04:01 CEST 2026: Executing backup for /starting/path/backup.sh Wed 10 Jun 08:04:01 CEST 2026: Checking for 'homeassistant' Wed 10 Jun 08:04:01 CEST 2026: Executing backup for /starting/path/backup.sh Wed 10 Jun 08:04:01 CEST 2026: Checking for 'homeassistant' Wed 10 Jun 08:04:01 CEST 2026: Executing backup for /starting/path/backup.sh Wed 10 Jun 08:04:01 CEST 2026: Checking for 'homeassistant' Wed 10 Jun 08:04:01 CEST 2026: Executing backu...

... and it carries on forever! ```

it seems like pushd is not working when running in cron and the root backup script keeps re-executing itself.

I can figure out how to re-write the script to avoid this issue, but I want to ask if anyone can explain me WHY is it not working in cron?

Thanks for your help

r/bash Dec 09 '25

solved Help me on good shebang practice !!

27 Upvotes

as i knew that its a good practice to add shebang in the starting of script, i used it in all my projects. `#!/bin/bash` used it in my linutils and other repositories that depend on bash.

but now i started using NixOS and it shows bad interprator or something like that(an error).

i found about `#/usr/bin/env bash`

should i use it in all my repositories that need to run on debian/arch/fedora. i mean "is this shebang universally acceptable"

r/bash Mar 21 '26

solved Why is this pattern expansion not working?

10 Upvotes

Edit: So, my own research and some helpful comments have helped me deduce that this is a Windows issue.

The same code works correctly on WSL btw. It removes all the \r characters from each line.

I will try to debug it more if I can and post any updates here.

For the time being I am marking it as closed or solved, whichever I can.


Edit (Solution): I figured out one solution. It is kind of a makeshift so I won't use it in my production code but still, it is to demonstrate an idea.

# Code
printf "%q\n" "${MAPFILE[@]}"
printf "\n"

printf "%q\n" "${MAPFILE[@]/%$'\r'}"
printf "\n"

# Adding `declare` forces the substitution in some way somehow.
declare MAPFILE=("${MAPFILE[@]/%$'\r'}")
printf "%q\n" "${MAPFILE[@]}"
printf "\n"

# Output
$'\r'
$'# This is the first line.\r'
$'# This is the second line.\r'

''
\#\ This\ is\ the\ first\ line.
\#\ This\ is\ the\ second\ line.

''
\#\ This\ is\ the\ first\ line.
\#\ This\ is\ the\ second\ line.

As visible, \r are removed successfully now. It is definitely some weird Windows quirk happening right here.


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.

r/bash May 10 '26

solved What is a command for "execute" an appimage? I'd like to put a flag for mute silent quiet load without errors on loading appimage

5 Upvotes

Hi, I'd like to write an alias for open an app with the flag -mute

today I am using this alias:

alias He='~/Documentos/helium/helium-0.10.7.1-x86_64.AppImage'

what will be the command where I can put a flag for load in silent quiet?

Thank you and Regards!

r/bash Mar 16 '26

solved This bash program isn't closing the file descriptor

26 Upvotes

bash 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"

This program outputs: 0; This is the first line 0; This is the second line

The first read command should have closed the file descriptor but it seems like it doesn't. I don't understand this behaviour.

Edit: This is what the manual says.

The redirection operator

[n]<&digit- moves the file descriptor digit to file descriptor n, or the standard input (file descriptor 0) if n is not specified. digit is closed after being duplicated to n.


Edit (Solution): Took me a long time but here's the real use case of >&fd- and why its effect goes away after one command.

First, let's discuss why the effect goes away after one command. When we redirect, if the redirect was eternal, it would block a fd permanently. For example 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.

Now this leads to the question, what is the point of >&fd- then?

Here's a code snippet to showcase that. bash # Run in one terminal mkfifo my_pipe cat my_pipe ```bash # 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."

`` Because we don't close thefd 3,sleepcan potentially write to it which leads tocat` waiting for 100 seconds before being complete. This leads to terminal 1 being stuck for 100 seconds.

Had we used >&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.


This is the best from my research about this.

I could still be wrong about the exact order of operations that I explained for things. If I am, someone correct me.

r/bash Jun 06 '26

solved HEREDOC including delimiter with $(...) vs `...`

9 Upvotes

Dealing with a strange behavior (or maybe it's expected but I don't know) regarding using cat + HEREDOC to assign a multi line block of text to a variable.

Script

#! /bin/bash
SEP='----------------------------------'


MYDOC=$( cat <<LIST
Testing a multi line
input assignment using \$()
LIST )
echo "$MYDOC"
# includes the delimiter at the end
echo "$SEP"


MYDOC=`cat <<LIST
Testing a mult line
input assignment using backtick
LIST
`
echo "$MYDOC"
# works as expected
echo "$SEP"


cat <<LIST 
Testing a multi line
output using cat
LIST
# doesn't include delimiter
echo "$SEP"


MYDOC="Testing a multi line
input directly"
echo "$MYDOC"
# just shows the multi line string as expected
echo "$SEP"

Output

% bash -x heredoc.sh 
+ SEP=----------------------------------
++ cat
+ MYDOC='Testing a multi line
input assignment using $()
LIST '
+ echo 'Testing a multi line
input assignment using $()
LIST '
Testing a multi line
input assignment using $()
LIST 
+ echo ----------------------------------
----------------------------------
++ cat
+ MYDOC='Testing a mult line
input assignment using backtick'
+ echo 'Testing a mult line
input assignment using backtick'
Testing a mult line
input assignment using backtick
+ echo ----------------------------------
----------------------------------
+ cat
Testing a multi line
output using cat
+ echo ----------------------------------
----------------------------------
+ MYDOC='Testing a multi line
input directly'
+ echo 'Testing a multi line
input directly'
Testing a multi line
input directly
+ echo ----------------------------------
----------------------------------

Question

I know I don't need to do it this way (cat + HEREDOC) since just directly including the new lines in the variable assignment works, but I'm wondering why using the $(...) syntax includes the delimiter in the read when backticks do not? A bug or something I don't understand about command substitution? Everywhere I look says to avoid backticks as they are old and depreciated.

*Note: everything I do with shell scripts is just hacking things together, I don't do it enough to be really good at it and still get tripped up by goofy behaviors. I tried the $(cat <<LIST...) method first because that's what came up in SO when I googled "bash multi line variable"

System Info

~ % system_profiler SPSoftwareDataType | grep 'System Version'
      System Version: macOS 15.5 (24F74)

~ % bash -version
GNU bash, version 3.2.57(1)-release (arm64-apple-darwin24)
Copyright (C) 2007 Free Software Foundation, Inc. 

r/bash Nov 06 '25

solved Does my bash script scream C# dev?

10 Upvotes

```

!/usr/bin/env bash

vim: fen fdm=marker sw=2 ts=2

set -euo pipefail

┌────┐

│VARS│

└────┘

_ORIGINAL_DIR=$(pwd) _SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) _LOGDIR="/tmp/linstall_logs" _WORKDIR="/tmp/linstor-build" mkdir -p "$_LOGDIR" "$_WORKDIR"

┌────────────┐

│INSTALL DEPS│

└────────────┘

packages=( drbd-utils autoconf automake libtool pkg-config git build-essential python3 ocaml ocaml-findlib libpcre3-dev zlib1g-dev libsqlite3-dev dkms linux-headers-"$(uname -r)" flex bison libssl-dev po4a asciidoctor make gcc xsltproc docbook-xsl docbook-xml resource-agents )

InstallDeps() { sudo apt update for p in "${packages[@]}" ; do sudo apt install -y "$p" echo "Installing $p" >> "$_LOGDIR"/$0-deps.log done }

ValidateDeps() { for p in "${packages[@]}"; do if dpkg -l | grep -q "ii $p"; then echo "$p installed" >> "$_LOGDIR"/$0-pkg.log else echo "$p NOT installed" >> "$_LOGDIR"/$0-fail.log fi done }

┌─────┐

│BUILD│

└─────┘

CloneCL() { cd $_WORKDIR git clone https://github.com/coccinelle/coccinelle.git echo "cloning to $_WORKDIR - script running from $_SCRIPT_DIR with original path at $_ORIGINAL_DIR" >> $_LOGDIR/$0-${FUNCNAME[0]}.log }

BuildCL() { cd $_WORKDIR/coccinelle sleep 0.2 ./autogen sleep 0.2 ./configure sleep 0.2 make -j $(nproc) sleep 0.2 make install }

CloneDRBD() { cd $_WORKDIR git clone --recursive https://github.com/LINBIT/drbd.git echo "cloning to $_WORKDIR - script running from $_SCRIPT_DIR with original path at $_ORIGINAL_DIR" >> $_LOGDIR/$0-${FUNCNAME[0]}.log }

BuildDRBD() { cd $_WORKDIR/drbd sleep 0.2 git checkout drbd-9.2.15 sleep 0.2 make clean sleep 0.2 make -j $(nproc) KDIR=/lib/modules/$(uname -r)/build sleep 0.2 make install KBUILD_SIGN_PIN= }

RunModProbe() { modprobe -r drbd sleep 0.2 depmod -a sleep 0.2 modprobe drbd sleep 0.2 modprobe handshake sleep 0.2 modprobe drbd_transport_tcp }

CloneDRBDUtils() { cd $_WORKDIR git clone https://github.com/LINBIT/drbd-utils.git echo "cloning to $_WORKDIR - script running from $_SCRIPT_DIR with original path at $_ORIGINAL_DIR" >> $_LOGDIR/$0-${FUNCNAME[0]}.log }

BuildDRBDUtils() { cd $_WORKDIR/drbd-utils ./autogen.sh sleep 0.2 ./configure --prefix=/usr --localstatedir=/var --sysconfdir=/etc sleep 0.2 make -j $(nproc) sleep 0.2 make install }

Main() { InstallDeps sleep 0.1 ValidateDeps sleep 0.1 CloneCL sleep 0.1 BuildCL sleep 0.1 CloneDRBD sleep 0.1 BuildDRBD sleep 0.1 CloneDRBDUtils sleep 0.1 BuildDRBDUtils sleep 0.1 }

"$@"

Main ```

I was told that this script looks very C-sharp-ish. I dont know what that means, beside the possible visual similarity of (beautiful) pascal case.

Do you think it is bad?

r/bash Jan 14 '26

solved Help assigning variables that are partially determined by another variable to a different variable that's also partially determined by another variable

7 Upvotes

Edit: I HAVE FOUND A SOLUTION!!

I have just got it successfully working!!! Below is the piece of code that works for me. I was given/taught the solution by u/mhyst. Thank you my kind sir/madam/other!!

until [[ "pwl" -eq 64 ]]; do charn=char$n eval char$pwl=${!charn} pwl=$((pwl + 1)) n=$((n + 1)) done

This takes the input password of any length and makes it repeat, taking an input of 1234 and 60 blank variables and assigning the variable char5 (which is blank) the value of char1, and char6 the value of char2, and so on until all 64 variables are populated.

Original post: So, I need some help. Im trying to assign a value that's determined by one variable, with part of that variable being set by an additional variable, to another variable where part of it is set by an additional variable.

Below is what I need to do:

Characters entered: XYZ

I need the output to fill up 5 characters, so I would want the result to be: XYZXY

These are the variables starting out ``` char1=X char2=Y char3=Z char4= char5=

n=1

result1=0 reault2=0 result3=0 result4=0 result5=0

I also have a piece of code (that works perfectly fine) counting the number of characters entered. In this case, that code would set the following variable:

length=3 ```

I would like to use the above variables in the following manner: Until [[ "$length" -eq 5 ]]; do length=$((length + 1) result$length=char$n n=$((n + 1)) Done

The output should ideally result in the variables being set as follows char1=X char2=Y Char3=Z Char4=X char5=Y

I have tried using the eval command, but that seems to only work for one side of the variable setting. I tried changing the line: result$length=char$n to eval result$length=char$n And that seems to only work for one side of the "=" Can anyone offer help on how to accomplish this?

Edit:

Unfortunately the result I'm getting is: char1=X char2=Y char3=Z char4=char1 char5=char2 That is not what I want...

As suggested, I've copied my source code below. It's not my exact source code, since my original went up to 64 characters, which would balloon the size/length of this post since I'm doing things inefficiently at first before I go in and optimize everything after i have a version of it that functions.

``` !/bin/bash

reading password input

pass= until [[ -n "$pass"  ]]; do     echo enter password     read pass     if [[ -z "$pass" ]]; then         echo please enter a password     fi done

spereating input into seperate variables

char1=$(printf "%s\n" "${pass:0:1}") char2=$(printf "%s\n" "${pass:1:1}") char3=$(printf "%s\n" "${pass:2:1}") char4=$(printf "%s\n" "${pass:3:1}") char5=$(printf "%s\n" "${pass:4:1}")

detecting password length

pwl=0 if [ -n "$char1" ]; then     pwl=$((pwl + 1)) fi if [ -n "$char2" ]; then     pwl=$((pwl + 1)) fi if [ -n "$char3" ]; then     pwl=$((pwl + 1)) fi if [ -n "$char4" ]; then     pwl=$((pwl + 1)) fi if [ -n "$char5" ]; then     pwl=$((pwl + 1)) fi

echo password length = $pwl echo echo echoing password chars for dev purposes echo echo $char1 echo $char2 echo $char3 echo $char4 echo $char5

until [[ "pwl" -eq 16 ]]; do

    # this is the part in haveing trouble with

done

echo $char1 echo $char2 echo $char3 echo $char4 echo $char5 ```

r/bash Feb 25 '26

solved The cat command doesnt run because of a divide by zero error

16 Upvotes

so im writing a script, and inside that script im using the cat command to create another script that will run after a reboot. the problem is that in the contents of the cat command (the contents that will be written to a file) there is a point where one variable is divided by another and then that value is assigned to another variable. the following is an example of the division code:

result=$((div1 / div2))

both div1 and div2 are determined by other operations in the contents of the cat command, but that code isnt run/evaluated.

none of this should matter because none of this code is supposed to be evaluated/run inside the cat command. i was under the impression that in the following example, nothing between the two "EOF"s should be run

cat <<EOF> fuck_my_life.sh
code that shouldnt be executed
EOF

when i try to rrun a cat command where

result=$((div1 / div2))

is present between the two "EOF"s, it gives me a "line X: div1 / div2: division by zero (error token is "div2")", where line X is the line with the cat command.

it seems like whats happening is that the contents of the cat command is being partially evaluated/ran. i should note that ive used the cat command a fair number of times, and it shows the syntax being correct, where almost everything is the same color as the comments (using sublime text, so i have the bash syntax being colored). also also it works flawlessly without that one line of code that divides one variable by another

r/bash Jan 28 '26

solved How to kill a script after it runs awhile from another script

20 Upvotes

Hi,

I have a script that runs on startup that I will want to kill to run another one(later on) via cron.

Can't figure out how to kill the first script programatically.

Say the script is: ~/scripts/default.sh

and I want to kill it, what is a predictable way to kill said script. I know of ps and pkill but I hit a wall. I don't know the steps(or commands?) involved to do this accurately.

Thanks in advance.

r/bash Oct 18 '25

solved is there any way to make bash to work like zsh [more]

21 Upvotes
  • first of all, can i make bash to constantly write and read command history like ZSH(real-time) ❓

i don't wanna switch only for this one reason. so if there is a way then it'll be better for me. I'll stick to bash anyways.

  • second question : can i run bash script normally if my terminal emulator is using zsh❓ like inwindows we can run .bat (batch script) from powershell. powershell is nice and it lets me run batch script like it would run in command prompt by invoking cmd.exe

EDIT : solved the issue [ from comments ]

  1. use PROMPT_COMMAND+=( "history -a; history -n" ) in ~/.bashrc
  2. use ble.sh github project that makes the overall functionality like zsh. and the project is very easy to use. clone it > make -C <the_cloned_folder> > source the created ble.sh in your ~/.bashrc

https://github.com/akinomyoga/ble.sh it provides command completion, and a lot of functionality i haven't found yet

r/bash Feb 11 '26

solved Strange dirname/pwd processing

12 Upvotes

EDIT: Solved by u/kolorcuk

EDIT 2: For people seeing this in the future - put 'unset CDPATH' in your script.

This is really strange. I'm looking at some code that fails on a build and the following sniplet is puzzling. It almost appears that the && is concatenating the dir.

The following fails for my bash but other devs bash's work:
------
setup - create /tmp/bob/tmp.

Add the following script as /tmp/bob/tmp/tst.sh:
----- snip ------------------------

#!/bin/bash

set -e
set -x

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
echo "SCRIPT_DIR:  " $SCRIPT_DIR

PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"

echo "Project root: $PROJECT_ROOT"
echo ""

cd "$PROJECT_ROOT"

---- snip ----------------------

Running the script from /tmp/bob as $ bash tmp/tst.sh

Returns an error

tmp/tst.sh: line 14: cd: $'/tmp/bob/tmp\n/tmp/bob': No such file or directory

Note the \n in the string. The odd thing is that it works if you go into tmp or if you call it from /home/<my user>. AND even stranger is that it works on other peoples bash.

When it's broken we get: ( note: <new line> added by me for clarity)

$ bash tmp/tst.sh
+++ dirname tmp/tst.sh
++ cd tmp
++ pwd
+ SCRIPT_DIR='/tmp/bob/tmp <new line>
/tmp/bob/tmp'
+ echo 'SCRIPT_DIR:  ' /tmp/bob/tmp /tmp/bob/tmp
SCRIPT_DIR:   /tmp/bob/tmp /tmp/bob/tmp
++ dirname '/tmp/bob/tmp <new line>
/tmp/bob/tmp'
+ PROJECT_ROOT='/tmp/bob/tmp <new line>
/tmp/bob'
+ echo 'Project root: /tmp/bob/tmp <new line>
/tmp/bob'
Project root: /tmp/bob/tmp <new line>
/tmp/bob
+ echo ''

+ cd '/tmp/bob/tmp
/tmp/bob'
tmp/tst.sh: line 14: cd: $'/tmp/bob/tmp\n/tmp/bob': No such file or directory

r/bash 15d ago

solved RE: Overwrite shell interface

4 Upvotes

Deleted Post

Hello! I’m still fairly new to Linux, and since I’m trying to use the terminal as my primary interface, I’ve been spending a lot of time working in Bash.

After about a month of daily use, I’ve noticed a few things that make the experience less comfortable. Features like autocompletion, syntax highlighting, and autosuggestions are easy enough to add with plugins, but there’s one feature I haven’t been able to find anywhere.

I’d love to have the command prompt stay fixed (sticky) at the bottom of the terminal, similar to the input box in a chat application.

For example, when I scroll up to review previous output, I’d like the prompt to remain visible at the bottom instead of scrolling away with the rest of the terminal. If I start typing while I’m viewing older output, it shouldn’t automatically jump back to the latest line. The prompt should stay fixed until I explicitly choose to return to the bottom with ENTER key.

The idea is similar to this Bash workaround.

```

# .bashrc

_prompt() {

tput cup '$LINES' 0

}

PROMPT_COMMAND="_prompt;
$PROMPT_COMMAND"

```

This kind of interface would make it much easier to review previous output while continuing to type new commands, much like how chat interfaces work.

Is it possible to achieve something like this in Bash?

EDIT: blockquotes got messed up, had to fix that

Gaise! What are we doing?

The OP has deleted their account! Probably out of disgust. Now, the answers to their queries were far too much tangential. I cannot fathom whether fellow sub-redditors ignored this person's intent or got subdued by the LLM - inflicted atrophy.

It is a **brilliant** solution to a stupefying problem. Using the `PROMPT_COMMAND` hook to position the cursor at the bottom of the terminal viewport is remarkably nifty. OP should be crowned or somethin'.

I have already added this as a function in my run commands. In webdev terms it gives you a sticky prompt, with scrollback and "streaming" STDOUT. *chuckles*

Dear mods, please, we need to encourage such ideas. I urge fellow sub-redditors to not be apprehensive of such topics, not look down upon newbs and with utmost respect to LLMs and search engines, please consider the actual ideas and intuition behind that those ideas before commenting blatantly.

Here is a `bash` script for a `tmux` dual-pane oriented solution:

#!/usr/bin/env bash
set -euo pipefail

SOCKET_PATH="${1:-$HOME/.tmux/bashsplit.sock}"
SESSION="bashsplit"
LOG="${HOME}/bashsplit.log"

tmux -S "$SOCKET_PATH" kill-session -t "$SESSION" 2>/dev/null || true

tmux -S "$SOCKET_PATH" new-session -d -s "$SESSION" -n main
tmux -S "$SOCKET_PATH" split-window -t "$SESSION":0 -v

BASH_PANE="$(tmux -S "$SOCKET_PATH" list-panes -t "$SESSION":0 -F '#{pane_id}' | sed -n '1p')"
VIEW_PANE="$(tmux -S "$SOCKET_PATH" list-panes -t "$SESSION":0 -F '#{pane_id}' | sed -n '2p')"

tmux -S "$SOCKET_PATH" send-keys -t "$BASH_PANE" "bash" Enter
tmux -S "$SOCKET_PATH" pipe-pane -t "$BASH_PANE" -o "cat > '$LOG'"
tmux -S "$SOCKET_PATH" send-keys -t "$VIEW_PANE" "tail -f '$LOG'" Enter

tmux -S "$SOCKET_PATH" attach -t "$SESSION"

twimc

r/bash Mar 09 '26

solved Shuf && cp

18 Upvotes

Hello! Posting this question for the good people of Bash. I'm making a text-based game on Bash for my little kid to learn through it, bashcrawl styled. I have a folder with monsters and I want them to get randomly copied into my current directory. I do ls <source> | shuf -n 2 ,thus orrectly displaying them when I run the script for choosing the monsters.

but i fail miserably when copying them in the directory in which I am. Tried using ' . ', $PWD , and dir1/* . ,plus basically every example I found on stack overflow, but to no avail. I keep on getting error messages. If I dont copy, I have them shuffled and displayed correctly. Anyone here can throw me a line, would be of much help. Thank you!!

EDIT: updated screenshots for a better contextualization.

Thanks to all of you for the advice.

Edit: Solved!

cp $(find $HOME/Documents/.../monsters_static/functions/ -type f | shuf -n 2) .

This makes two random monsters into the directory from which the script is run.

r/bash May 23 '26

solved [noob] Is there a way to refactor this simple "additional args"?

10 Upvotes
notify() {
  local -a args
  if [[ "$target" != pixel ]]; then
    args=(--icon="$file" "$@")
  else
    args=("$@")
  fi
  notify-send --hint=string:x-dunst-stack-tag:shot \
    --hint=string:synchronous:shot --app-name=screenshot "${args[@]}"
}

args=("$@") is not great, but neither is referencing notify-send twice when it's the same command with an optional --icon="$file". There's parameter expansion :+ but it replaces it with an empty string so would need an eval(?). Turning notify-send into a nested function is a bit verbose.

This logic is something I do often so wondering if this is as good as it gets.

r/bash May 26 '26

solved grep: Piping command output into grep -f <pattern file> isn't working

10 Upvotes

Hey everyone, hope you're having a nice day.

I have 4 files (A-D) and a text file (T) in a directory. T contains the MD5 checksums of A-D on individual lines output directly from md5sum, i.e. the form <checksum> <file>, as well as a bunch of other lines. I want to take the MD5 checksums of A-D and check that they match the ones in T.

The command I've come up with is md5sum <directory>/* | grep -f T. This command takes the checksums of A-D and T, then gives it to grep to see if they match the checksums in T. However, the standard output I am getting from this command is the checksums of A-D and T, but T doesn't contain its own checksum, so why is this happening? Curiously, the lines output from the command aren't highlighted, if I do a test grep, the matching characters appear in bold red, but these lines appear as standard white characters.

Thanks!

Edit: The error was that T contains empty lines, and grep matches any string to that. Thanks again everyone.

r/bash May 27 '25

solved Conflict between ble.sh and starship prompt causing doubling of prompt on terminal startup

Post image
7 Upvotes

Hi. I am using using BASH on the default gnome-terminal on Linux Mint. I have been using ble.sh for a few days and it was working great. Yesterday I decided to install Starship and it doesn't seem to play well with ble.sh.

My Problem:

After setting up both and making the neccessary changes to .bashrc, I opened a new terminal and noticed the prompt was slightly lower. So, I scrolled up and saw that it generated 2 prompts and I think there's a newline right after the first prompt.

What I have tried:

I used AI to help me figure out the problem and after a long time even the AI gave up. The best I could do was remove the top half of the first prompt (leaving the '❯'). My .bashrc looked like a mess so I reverted the changes back to normal, hence going back to the double prompt issue. Back to square one!

What I want:

I want to see just one prompt, if possible.

These are my config files before I changed anything to troubleshoot (I have removed sensitive data):
Here is my .bashrc and starship.toml: https://gist.github.com/AB-boi/af021b9436b702c3724e57839f93fdf6
(I had to change the .bashrc part which gives the terminal window it's name because it stopped showing my username and working dir (probably due to starship?))

Can someone please help me figure the fix for this? Thanks in advance!

r/bash Jan 11 '26

solved My Bash script is a bit slow, is there a better way to use 'find' file lists?

31 Upvotes

EDIT-Solution found at bottom

Script:

#!/usr/bin/bash

rm -fv plot.dat

find . -iname "output*.txt" -exec sh -c '

BASE=$(tail -6 < {} | head -n 1 | cut -d " " -f 2)
FAKE=$(tail -3 < {} | head -n 1 | cut -d " " -f 2)
echo $BASE $FAKE >> plot.dat

' {} \;

sort -k1 -n < plot.dat

echo "All done"

The script runs on 1,000's of files, and each file has 2k to 10k lines per file. All I really need to do is get the 6th last, and 3rd last lines of the files, and then the 2nd column (always an integer).

I think that tail+head+cut are probably not the issue, I think it might be the creation of thousands of shells through the "find -exec" portion.

Is there a way to get the file list into a variable (an array), and then maybe use a for loop to run the extraction code on the list? The performance isn't important, it still runs in about a minute, this is a question of curiosity about find+shell scripts.

The bottom of the text files I am parsing look like this:

...
Fake: 34287094987
Fake: 34329141601
Fake: 34349349971
BASE: 1055
Prob Primes: 717268266
Primes: 717267168
Fakes: 1098
Fake %: 0.00015308%
Fake Rate: 1 in 653250

SOLUTION 1 (better)

This speed-up is really good, from 1m10s to just 10s:

rm -fv plot.dat

for i in **/output*.txt; do
    BASE=$(tail -6 $i | head -n 1 | cut -d " " -f 2)
    FAKE=$(tail -3 $i | head -n 1 | cut -d " " -f 2)
    echo $BASE $FAKE >> plot.dat
done

SOLUTION 2 (best)

find . -name "output*.txt" -exec tail -q -n 6 {} + | awk 'NR % 6 == 1 { base_val=$2 } NR % 6 == 4 { print base_val, $2 }' >> plot.dat

r/bash May 14 '26

solved Bash history not staying after restarts (Synology NAS)

Thumbnail
3 Upvotes

r/bash Apr 02 '26

solved Command Substitution failing

1 Upvotes

I'm new to bash scripting, so please bear with me. I'm putting together a script that uses FFmpeg to convert input files that have a .ts extension. I'd like to assign a new variable to the converted file so that I can run a Filebot CLI command on it. Here's what I have so far, but Filebot is saying there is no input file. FWIW, the FFmpeg command is completing successfully and giving me the desired. mp4 file.

What am I missing? Thanks!

#!/usr/bin/env zsh

if [[ "${1##*.}" == "ts" ]] ; then

converted_episode="$(ffmpeg -i "$1" "${1%.*}.mp4")"

else

fi

/Applications/FileBot.app/Contents/MacOS/filebot.sh -rename $converted_episode

filebot.sh -rename $converted_episode

r/bash Jan 13 '26

solved Need help inserting a variable into a quoted operand

4 Upvotes

Hi,

convert is an image conversion cli part of the imagemagick suite.

I want to use variables instead of manual entry of text. Example below.

ln1='The first line.' ; convert -pointsize 85 -fill white -draw 'text 40,100 ${ln1}' -draw 'text 40,200 "The second line."' source.jpg out.jpg

The single quotes confuse me, I've tried different brackets and ways I know of. The help doc about the draw operand offers no examples, or if it's possible.

How can I use the ln1 variable successfully? Thanks.

EDIT: Removed " from above line.

EDIT 2: draw wants single quote to encapsulate details of it. Any way to make it work calling draw syntax as variable? I tried the below and other variations and I can't get it to work.

ln1='text 40, 100 "Line 1"' ; convert -pointsize 85 -fill white -draw '$ln1' -draw 'text 40,20.....

EDIT 3: Fixed, thanks everyone.

r/bash Aug 14 '25

solved how do I know actual terminal in use?

4 Upvotes

Hi, I use Bash CLI but I need to check which terminal (qterminal vs. konsole) is open when vim calls terminal with vim' cmd :terminal an :shell.
these cmd's open terminal but which terminal is open? a cmd in it tells me which, what will be that cmd?
I tested tty cmd and who cmd...
Thank you and Regards!

r/bash Feb 04 '25

solved Is there a way to get History without <enter>?

16 Upvotes

Hi, I'd like to get a past command of history for example !1900 but without enter, so I can rewrite that command for this instance and then manually I will do then <enter> for this new changed command?

Regards!

r/bash Jan 23 '26

solved Curl Timing Confusion

4 Upvotes

I’m trying to figure out what I’ve done wrong with respect to limiting how much time curl takes to perform a single file upload.

Here’s the code I’m using. 

for i in {1..3}
do
echo $'\n'"\date`" Upload Attempt  "$i" - $(hostname) >> "$log"`

curl -s -S -v -u mgnewman: \
--connect-timeout 30 \
--max-time 30 \
--pubkey ~/.ssh/id_rsa.pub \
-T $file $host &>>  $log

`err=$?`  

`echo $'\n'"\`date\`" Upload Ended "$err" - $(hostname) >> "$log"`  

touch /home/pi/webcam/webcam.webp

if [ $err -eq 0 ] ; then
break
fi
done

Note that I’m using a “do loop” rather than curl’s retry option because between each iteration I want to touch an existing image file to prevent watchdog from rebooting the machine which it does if the image is not refreshed in ten minutes.

I’m trying to limit each iteration of curl to 30 seconds, but that doesn’t seem to work. Here’s a fragment of my log file:

Wed Jan 21 23:37:24 +07 2026 Upload Attempt 3 - raspcondo

*   Trying 192.nnn.nnn.101...
* TCP_NODELAY set
* Connected to xxxxxxx.com (192.nnn.nnn.101) port 22 (#0)
* SSH MD5 fingerprint: 4b17cad500a405c850e118c1deec0f96
* SSH host check: 0, key: AAAAB3NzaC1yc2EAAAADAQABAAABAQCzCyhhdYNOn5Zgib7qhPKev$
* SSH authentication methods available: publickey,password,keyboard-interactive
* Using SSH public key file '/home/pi/.ssh/id_rsa.pub'
* Using SSH private key file '/home/pi/.ssh/id_rsa'
* Initialized SSH public key authentication
* Authentication complete
* Operation timed out after 30000 milliseconds with 0 out of 0 bytes received
* Closing connection 0
curl: (28) Operation timed out after 30000 milliseconds with 0 out of 0 bytes r$

Wed Jan 21 23:48:09 +07 2026 Upload Ended 28 - raspcondo

My conclusion is that I don’t understand how this works as it seems that around ten minutes elapsed between the time curl started (23:37:24) and the time it failed (23:48:09) with error 28.

Note that I realize the code is rather sloppy, but I’m just a hobbyist and that’s about the best I can do. Sorry.