Unix & Linux Stack Exchange
Q&A for users of Linux, FreeBSD and other Unix-like operating systems
Latest Questions
-3
votes
2
answers
226
views
Is Bourne shell shebang #!/bin/sh expecting BASH POSIX-correct?
I've recently been playing with the legacy Bourne Shell from the GitHub repo [heirloom-sh](https://github.com/grml/heirloom-sh). It's installed at `/usr/local/bin/sh` with no symlinks. One script is invoking it via `#!/bin/env sh`. *I'm running Manjaro with system and packages fully up to date as of...
I've recently been playing with the legacy Bourne Shell from the GitHub repo [heirloom-sh](https://github.com/grml/heirloom-sh) . It's installed at
/usr/local/bin/sh
with no symlinks. One script is invoking it via #!/bin/env sh
.
*I'm running Manjaro with system and packages fully up to date as of this post (vscodium-bin
1.99.02289-1, Manjaro 6.12.20-2-MANJARO). I posted concisely on their forum , but this issue goes way beyond even Arch stacks, affecting all Linux development.*
## Background
Most of our Linux scripts are written for BASH (/bin/bash
) and cannot work for Bourne Shell (implied by /bin/sh
, but not reliable ). But, many coders still put #!/bin/sh
for the shebang (#!/...
) anyway, then code as if for the BASH #!/bin/bash
.
For most systems, /bin/sh
is a link to /bin/bash
, letting everything for BASH work in a mis-labaled Bourne Shell script. This has resulted in some sloppy programming practices and breaks the rule from Chemistry class: "Never make labels lie."
For Debian, /bin/sh
is a link to /bin/dash
(Debian Almquist shell, POSIX minimal), carrying many Bourne Shell limits. So, Debian/Ubuntu devs might not run into the same problems of BASH scripts still working with #!/bin/sh
. Thus, this may mostly be a non-Debian dev issue.
...mostly.
# Examples of resulting errors
## Eg. VSCodium
I first noticed this as a non-system issue with the AUR packages vscodium and vscodium-bin (I'm using vscodium-bin
).
/opt/vscodium-bin/bin/codium
(where VSCodium resides) had this as line 1:
#!/usr/bin/env sh
...which would not start from the GUI, and then from the CLI threw this error:
/opt/vscodium-bin/bin/codium: syntax error at line 20: `YN=$' unexpected
I had two solutions:
1. Comment and changed the shebang line to this:
#!/usr/bin/bash
...then it worked.
2. Remove /usr/local/bin/sh
(my legacy sandbox authentic Bourne shell, see above)...
I reversed line 1 that so that /opt/vscodium-bin/bin/codium
once again had this as line 1:
#!/usr/bin/env sh
...as it does OOB, then I removed /usr/local/bin/sh
.
Then it also worked.
***Technically, #!/usr/bin/env sh
might not be POSIX compliant if it invokes BASH-only code.***
So, that would be an example of this coding issue happening with an actual project, VSCodium specifically.
## Eg. Manjaro Boot
I mentioned this in my Manjaro Forum post , but basically having /bin/sh
as an actual, true legacy /bin/sh
Bourne shell broke my boot sequence.
That tells me that many of my distro's most-current startup boot processes and scripts are actually using BASH code with a Bourne shell shebang.
On Arch, not only Manjaro, /bin/sh
is a symlink to bash
, presuming the same PWD; it isn't even an absolute link, but a relative link!
Arch:
# ls -l /bin/sh
lrwxrwxrwx 1 root root 4 May 5 2025 /bin/sh -> bash
The boot issue on Manjaro is unlikely from developers changing an Arch file with #!/bin/bash
into #!/bin/sh
. Many of our implied, forgotten, invoked system startup scripts are probably inherited from the runlevel era. This is a legacy issue, after all.
I'm scratching my head on how in the Linux-world that was even able to come from mainstream distro-level developers.
# Summary
We still have Bourne Shell artifacts in the form of #!/bin/sh
floating around out there, even in our most current Linux distros, still being created in the developer world. If ever /bin/sh
actually is /bin/sh
, many Linux systems won't boot! This makes big problems for any portability.
In fact, this might even be a security issue: Make /bin/sh
actually become /bin/sh
and every Linux server can't reboot.
___
These surrounding questions come to mind. How far does it reach into our Unix/Linux world to have /bin/sh --> bash
?
Is it POSIX compliant to use #!/usr/bin/env sh
, then invoke code that only works with #!/bin/bash
*and does not work* with #!/bin/sh
? If POSIX compliant, why and would it break any other coding guidelines?
Has the Linux world addressed BOLO to make sure we aren't using Bourne Shell (#!/bin/sh
) in our scripts unless we are writing for the legacy Bourne Shell last updated for capabilities in 1989? Should we all be looking through our code and removing any #!/bin/sh
meant to run on modern systems that probably have a link to /bin/bash
anyway? Even consider removing the /bin/sh
link to /bin/bash
altogether?
In light of not relying on sh at /bin/sh , if we thus should not use #!/bin/sh
in referencing BASH code (that is if), then *theoretically* should Debian scripts use #!/bin/dash
instead of #!/bin/sh
? Or, is Debian's dash
close enough to sh
that it fits current POSIX expectations?
How much has this already been discussed and what are the current resolutions across the Linux world?
Is there another reason we need "labels to lie" and that using #!/bin/sh
-labeled code (that can't run on actual 1989 Bourne Shell's /bin/sh
) is a good idea?
Does this issue only affect Linux or also Unix? Do Apple scripts use #!/bin/sh
with symlink?
Jesse
(355 rep)
Apr 5, 2025, 08:17 PM
• Last activity: Apr 12, 2025, 04:30 PM
9
votes
4
answers
2447
views
Is it potentially dangerous to run a bash script with sh?
So obviously when you run a Bash script with `sh` (as in `sh ./path/to/bash-script.sh`), you may experience errors in cases where sh is a symlink to a non-Bash shell that doesn't support a feature used in the script. What I'm curious about is, if there could be a case where a script designed for Bas...
So obviously when you run a Bash script with
sh
(as in sh ./path/to/bash-script.sh
), you may experience errors in cases where sh is a symlink to a non-Bash shell that doesn't support a feature used in the script.
What I'm curious about is, if there could be a case where a script designed for Bash, executed by dash or some basic POSIX shell would cause code to be executed that otherwise definitely would not have been executed.
Everything I've tested (e.g. command grouping (( ... ))
) simply causes the script to exit early when executed with a primitive POSIX shell, not causing any potential damage.
Forivin
(1193 rep)
Nov 20, 2024, 02:40 PM
• Last activity: Nov 23, 2024, 07:02 PM
0
votes
2
answers
1392
views
Dash gives error "sh: 1: cannot create : Directory nonexistent"
I am running the following script in Ubuntu 22.04: ``` #!/bin/bash logfile="/absolute/path/to/log.txt" find /absolute/path/to/haystack -type d -name "needle" -execdir sh -c 'pwd > $logfile' \; ``` The hope is that it would print the full directory path of each folder named `needle/` within the folde...
I am running the following script in Ubuntu 22.04:
#!/bin/bash
logfile="/absolute/path/to/log.txt"
find /absolute/path/to/haystack -type d -name "needle" -execdir sh -c 'pwd > $logfile' \;
The hope is that it would print the full directory path of each folder named needle/
within the folder haystack/
to the file log.txt
. Instead, it prints nothing but a long list of the error sh: 1: cannot create : Directory nonexistent
to the standard output (and it writes nothing to log.txt
).
This [answer](https://stackoverflow.com/a/66653290/) demonstrates that the error originates in Dash, not Bash. Since I'm using the Bash shebang, this means the error must stem from the use of -execdir sh
-execdir sh -c 'pwd > $logfile' \;
since in Ubuntu sh
is symlinked to Dash. My first theory was that Bash isn't passing its variable $logfile
to Dash. This [answer](https://unix.stackexchange.com/a/737106/) states that variables are copied to subshells, which was my understanding, but perhaps that doesn't hold true across completely different shells. To test it, I changed the shebang to #!/bin/sh
, which is Dash on this system. The result is the same, however: rows of the error sh: 1: cannot create : Directory nonexistent
.
**What causes this error to happen?**
Any help is appreciated, but please note that I've posted because I want to understand the origin of the error, just as the question asks. I'm not interested in any answer that takes a different approach to listing needle/
directories, unless that answer is accompanied by an explanation of why this script fails.
Borea Deitz
(170 rep)
Aug 29, 2024, 07:19 PM
• Last activity: Aug 30, 2024, 04:15 PM
0
votes
0
answers
35
views
Bash misinterpreting lenght of PS1 when using ANSI escape sequences
if i use the following ``` export PS1='\033[36m$ \033[0m' ``` Bash misunderstands the length of the prompt and starts line-wrapping too early. My assumption was that it is counting every character, but comparing `${#PS1}` to `$COLUMNS` shows that not to be the case. if i instead use the following ``...
if i use the following
export PS1='\033[36m$ \033[0m'
Bash misunderstands the length of the prompt and starts line-wrapping too early. My assumption was that it is counting every character, but comparing ${#PS1}
to $COLUMNS
shows that not to be the case.
if i instead use the following
export PS1='$ '
there is no issue
additionally, if i use dash
shell, this does not happen, so i know it is an issue with Bash, and not my terminal etc. however, if i launch dash
in vi mode with dash -V
or set -o vi
, the escape characters are ignored and not sent to my terminal at all. I assume this is a bug in dash
though, so i reported this on the dash
mailing list.
thanks
user21749640
(101 rep)
Aug 20, 2024, 09:17 PM
4
votes
2
answers
1018
views
Why does printf byte formatting fail when executed under `dash`?
The ASCII hex code for a zero is 0x30. Hence, you can print a zero by doing `printf '\x30'`, and it will print a zero. If you put this into a shell script called myScript.sh, and then execute `./myScript.sh`, it will also print a zero. But if you execute `sh -c printf '\x30'` or alternatively, `sh m...
The ASCII hex code for a zero is 0x30. Hence, you can print a zero by doing
printf '\x30'
, and it will print a zero.
If you put this into a shell script called myScript.sh, and then execute ./myScript.sh
, it will also print a zero.
But if you execute sh -c printf '\x30'
or alternatively, sh myScript.sh
, you will instead get the literal characters "\x30", rather than having it be interpreted as a single byte.
Why is that?
(Behavior has been observed on multiple machines, all of which I believe are running bash).
Murphy
(59 rep)
Dec 31, 2020, 10:05 PM
• Last activity: Apr 22, 2024, 11:48 AM
6
votes
1
answers
1175
views
Putting "$@" in a local variable in dash
I have a Bash function that does some string manipulation on its arguments as a whole (`"$@"`) by putting it in a local variable, something like this: ```sh my_func() { local args="$@" echo "args: " } my_func "$@" ``` When I run this in Bash, `args` contains all of the arguments that were passed: ``...
I have a Bash function that does some string manipulation on its arguments as a whole (
"$@"
) by putting it in a local variable, something like this:
my_func() {
local args="$@"
echo "args: "
}
my_func "$@"
When I run this in Bash, args
contains all of the arguments that were passed:
$ bash foo.sh foo bar baz
args:
However, if I run it in Dash, only the first argument is stored:
$ dash test.sh foo bar baz
args:
Reading [the section on local
in the Ubuntu Wiki's "Dash as /bin/sh" page](https://wiki.ubuntu.com/DashAsBinSh#local) , it seems that Dash is expanding the local args="$@"
line like so:
local args=foo bar baz
and therefore only putting "foo" in args
and declaring bar
and baz
as (local?) variables. In fact, if I add echo "bar: $bar"
to my_func
and run it with an =
in the arguments it seems to confirm that I am adding variables:
$ foo.sh foo bar=baz
args:
bar: baz
All this to say, is there a way to get the Bash-like behaviour (of $args
containing "foo bar baz") in Dash?
Harry Cutts
(242 rep)
Jul 25, 2019, 08:17 PM
• Last activity: Feb 15, 2024, 03:41 PM
1
votes
1
answers
178
views
Anyway to bind keyboard to dash (Debian Almquist Shell)?
Specifically Up/Down for history navigation. # What I already know I understand [`dash`](https://en.wikipedia.org/wiki/Debian_Almquist_shell#Dash) is a minimalistic, no bloat, (somewhat) strict POSIX shell. I understand the philosophy behind it, and the reason features, that have become basic in oth...
Specifically Up/Down for history navigation.
# What I already know
I understand [
dash
](https://en.wikipedia.org/wiki/Debian_Almquist_shell#Dash) is a minimalistic, no bloat, (somewhat) strict POSIX shell.
I understand the philosophy behind it, and the reason features, that have become basic in other interactive shells, are not present in dash
.
I've looked into the following resources:
* [man](https://www.man7.org/linux/man-pages/man1/dash.1.html) page
* [Arch Linux Wiki](https://wiki.archlinux.org/title/Dash) page
As well as a bunch of other pages and answers specific about history in dash
.
From my reading, I gather _there is_ a history mechanism, as well as a vi
mode.
However I can't find how to map the ` key, or the
[UP]/
[DOWN]` arrow keys (or any key) to any meaningful action.
No bind
or bindkey
builtin commands either.
My goal - make dash minimally usable as an interactive shell for debugging purposes.
# Questions
* Is there a default mapping?
* Is there a way to manipulate the keyboard mapping in dash?
* Is there another source of information that can shed some light on interactive usability of dash?
Lockszmith
(768 rep)
Jan 11, 2023, 10:58 PM
• Last activity: Jan 11, 2024, 06:37 AM
1
votes
0
answers
400
views
I get permission denied for a command in an sh script, but same command works from terminal
I have a service run by systemctl in RedHat 8.8. The service itself is relatively simple: ``` cat /etc/systemd/system/myservice.service [Unit] Description=My service After=network-online.target [Service] Type=forking User=myuser Group=mygroup Restart=no TimeoutSec=60 ExecStart=/usr/lib/myapp/service...
I have a service run by systemctl in RedHat 8.8. The service itself is relatively simple:
cat /etc/systemd/system/myservice.service
[Unit]
Description=My service
After=network-online.target
[Service]
Type=forking
User=myuser
Group=mygroup
Restart=no
TimeoutSec=60
ExecStart=/usr/lib/myapp/service.sh start
ExecStop=/usr/lib/myapp/service.sh stop
[Install]
WantedBy=multi-user.target
Sudoers file is set up so that all members of the "mygroup" are able to execute this service in the name of the "myuser":
%mygroup ALL = (ALL : myuser) NOPASSWD: /usr/bin/systemctl start myservice
The problem is within the service.sh file. The preamble is #!/bin/sh
. It tries to start a JBoss instance, and execute some actions, e.g.:
cat /dev/null > $JBOSS_CONSOLE_LOG
START_FILE="${JBOSS_HOME}/start_user"
ACCESS_USER="$(who am i | awk '{print $1}')"
echo "${ACCESS_USER}" > ${START_FILE}
Now, when I'm logged in with "myuser" over SSH, and I start this service by systemctl start myservice
, I get a bunch of permission denied errors for the above commands:
When trying to cat devnull into the JBOSS_CONSOLE_LOG:
/usr/lib/myapp/service.sh: line 82: /opt/myapp/home/domain/log/console.log: Permission denied
When trying to print into the START_FILE:
/usr/lib/myapp/service.sh: line 92: /opt/myapp/home/start_user: Permission denied
The file permissions are set up correctly as far as I can tell, everything is owned by "myuser" and "mygroup":
ll /opt/myapp
drwrwxr-x+ 11 myuser mygroup 4096 Nov 14 20:56 home
ll /opt/myapp/home
drwxrwxr-x+ 10 myuser mygroup 4096 Nov 14 20:29 domain
ll /opt/myapp/home/domain
drwxrwxr-x+ 10 myuser mygroup 4096 Nov 14 20:29 log
When I execute the same exact commands directly from the terminal, it works OK. When I made a simple test.sh file and put the commands there, again it worked OK. So something must change when running the service script, but I'm not sure why. I also noticed that the script tries to determine the ACCESS_USER variable like so:
ACCESS_USER="$(who am i | awk '{print $1}')"
And it gets an empty result. But when I run the same command on my terminal, it prints "myuser" correctly. It also works from my test.sh file.
Where should I start? This is a certain product I'm using so I'll be sure to contact their support, but maybe I'll get some ideas from here also.
--------------------------
Edit: thanks for the comments, I'll try to answer.
@Chris Davies: $JBOSS_CONSOLE_LOG is /opt/myapp/home/domain/log/console.log, $JBOSS_HOME is /opt/myapp, I already shared the owners in my original question. Also thanks for the explanation between "whoami" and "who am i", I have read upon them before, but now it is clear that I need a terminal for "who am i" to work.
@waltinator and @muru: this script is not running from crontab, it is executed when I start the mentioned service: systemctl start myservice
, see the service description in my original question. The "myuser" user is added to the sudoers file so that it can launch the service.
@rivimey: I'm printing the output of the "id" command and the "whoami" command, it shows the correct user:
echo "id = $(id), whoami = $(whoami)
id = uid=1001(myuser) gid=1001(mygroup) groups=1001(mygroup) context=system_u:system_r:unconfined_service_t:s0, whoami = myuser
Also when I check the running script in the "ps -ef" output, it also shows the correct user executing it.
--------------------------
Edit 2: ahh, it was SELinux... as I was typing my previous edit, I thought of disabling it, and now the service is working correctly. Strange, because I tried to check the audit logs, manually and with audit2allow command as well, I got some "missing type enforcement" rules, but nothing related to my application. If I don't get a better solution, I'll post this as answer.
Gábor Major
(111 rep)
Nov 14, 2023, 08:09 PM
• Last activity: Nov 15, 2023, 06:33 AM
12
votes
2
answers
11272
views
When sh is a symlink to bash or dash, bash limits itself to POSIX-compliance, so it should be 100% compatible with sh?
From [Difference between bash and sh][1]: [1]: http://www.linuxquestions.org/questions/programming-9/difference-between-bin-bash-and-bin-sh-693231/ > ABck to the question: If you have `/bin/sh` as a link to bash, then bash will not behave the same when called as `/bin/sh` as it does when called as `...
From Difference between bash and sh :
> ABck to the question: If you have
/bin/sh
as a link to bash, then bash will not behave the same when called as /bin/sh
as it does when called as /bin/bash
. When called as sh
, it will limit itself to mostly POSIX-compliance plus a limited set of extensions.
Does it mean that whenever I come across a shell script in Linux with a shebang to sh: #!/bin/sh
, even if on that distro, bin/sh
is a symlink to another shell, like dash or bash, it should be 100% compatible with the bourne shell, since it limit itself to a limited set of extension? So I could execute them in FreeBSD? Is there are exception to that? Or I should be safe to assume that it will work?
So if on a distro, bin/sh
is a symlink to bin/bash
, and a script use #!/bin/sh
and the script contain bashism, it will not run, since bash will like be in sh mode?
user1115057
(825 rep)
Aug 6, 2012, 01:42 AM
• Last activity: Oct 19, 2023, 07:44 AM
9
votes
1
answers
551
views
Why does exiting with a stored returncode of a nested command result in different returncodes in Dash and Bash?
Running bash -c 'bash -c "echo test1; exit 1;" &> /tmp/x; buildresult=$?; tail -n 100 /tmp/x; exit $buildresult;' results in `test1` being printed to console and `echo $?` to print `1` which in my understanding is correct, because the command should return with what the inner `[b/d]ash -c` returned...
Running
bash -c 'bash -c "echo test1; exit 1;" &> /tmp/x; buildresult=$?; tail -n 100 /tmp/x; exit $buildresult;'
results in
test1
being printed to console and echo $?
to print 1
which in my understanding is correct, because the command should return with what the inner [b/d]ash -c
returned whereas
dash -c 'dash -c "echo test1; exit 1;" &> /tmp/x; buildresult=$?; tail -n 100 /tmp/x; exit $buildresult;'
results in the same output, but returns with 0
according to echo $?
.
I'd like to understand this difference in order to broaden my understanding of shells and portable shell programming.
I'm using bash
4.4.12 and dash
0.5.8-2.3ubuntu1 on Ubuntu 17.10 (Artful Aardvark).
Kalle Richter
(2252 rep)
Nov 18, 2017, 07:04 PM
• Last activity: Oct 18, 2023, 08:03 PM
10
votes
6
answers
3943
views
Portable check empty directory
With Bash and Dash, you can check for an empty directory using just the shell (ignore dotfiles to keep things simple): set * if [ -e "$1" ] then echo 'not empty' else echo 'empty' fi However I recently learned that Zsh fails spectacularly in this case: % set * zsh: no matches found: * % echo "$? $#"...
With Bash and Dash, you can check for an empty directory using just the shell
(ignore dotfiles to keep things simple):
set *
if [ -e "$1" ]
then
echo 'not empty'
else
echo 'empty'
fi
However I recently learned that Zsh fails spectacularly in this case:
% set *
zsh: no matches found: *
% echo "$? $#"
1 0
So not only does the
set
command fail, but it doesn't even set $@
. I suppose
I could test if $#
is 0
, but it appears that Zsh even stops execution:
% { set *; echo 2; }
zsh: no matches found: *
Compare with Bash and Dash:
$ { set *; echo 2; }
2
Can this be done in a way that works in bash, dash and zsh?
user327359
Jan 7, 2019, 01:06 AM
• Last activity: Sep 27, 2023, 12:58 PM
5
votes
2
answers
743
views
dash maximum variable length under systemd
I have a shell script that uses a single variable as an associative array (one `KEY=VALUE` per line). Throughout the execution of the script, the variable is manipulated to add, remove or modify entries: Append: ``` lang-bash VARIABLE="$(printf "%s\n%s" "$VARIABLE" "KEY=VALUE")" ``` Modify: ``` lang...
I have a shell script that uses a single variable as an associative array (one
KEY=VALUE
per line).
Throughout the execution of the script, the variable is manipulated to add, remove or modify entries:
Append:
lang-bash
VARIABLE="$(printf "%s\n%s" "$VARIABLE" "KEY=VALUE")"
Modify:
lang-bash
VARIABLE="$(printf "%s\n" "$VARIABLE" | sed -E "s,^(KEY=).*$,\1VALUE,")"
Remove:
lang-bash
VARIABLE="$(printf "%s\n" "$VARIABLE" | grep -E -v "^KEY=.*$")"
When executed in a terminal (or as a service on an old machine under *sysv* through an init script), the script runs fine, but when run as a service under *systemd*, after a while, the script starts to spit out error messages in the log :
sh: printf: I/O error
After a lot of trial and error, I couldn't determine exactly what command(s) in the script produced those errors, but I noticed that they start to appear when the length of the variable reaches 8000 bytes (I guess 8192, but I couldn't pinpoint it exactly since whole lines are appended).
I'm pretty sure the variable length is the problem because I implemented a routine that trims the oldest entries of the array whenever the variable length approaches 8192 bytes, and now the script does run under systemd
for a long time without errors; but that's of course not ideal, as there is some information lost.
I searched the web for information about maximum variable length in shell scripts, but didn't find anything useful:
- dash
manual page doesn't say anything about maximum variable length.
- [GNU sed documentation](https://www.gnu.org/software/sed/manual/html_node/Limitations.html) says:
> For those who want to write portable *sed* scripts, be aware that some implementations have been known to limit line lengths (for the pattern and hold spaces) to be no more than 4000 bytes. The *POSIX* standard specifies that conforming *sed* implementations shall support at least 8192 byte line lengths. *GNU sed* has no built-in limit on line length; as long as it can *malloc()* more (virtual) memory, you can feed or construct lines as long as you like.
...but this applies to *line* length, not to the whole text length (the individual lines don't exceed 80 characters)
Anyway, since the errors appear only when the script is run through systemd
, I tried to increase LimitMSGQUEUE
and/or LimitSTACK
in the unit file, to no avail (this was a blind guess, as I don't understand exactly the concepts of message queues or process stack, but the numbers shown by systemctl show
looked like 8 KB or so). All other limits regarding memory (LimitRSS
, LimitAS
, LimitMEMLOCK
) seem high enough (way past 8192 bytes), so I don't know what to do next.
What can I do to get this script running under systemd
without errors when the variable length exceeds 8 KB ?
MoonSweep
(428 rep)
Apr 10, 2019, 10:07 AM
• Last activity: Sep 4, 2023, 11:57 PM
3
votes
1
answers
893
views
Debian /bin/sh in a Docker container never seems to look at .profile
I can not seem to get [dash](https://manpages.debian.org/bullseye/dash/dash.1.en.html) to look at $HOME/.profile: ``` pedz@Peace:s001 ~[S:hatred] % docker exec -it hatred-web-1 dash -i # cat $HOME/.profile PROOF=true; export PROOF PATH=/hatred/bin:$PATH; export PATH # env | sort BUNDLE_APP_CONFIG=/u...
I can not seem to get [dash](https://manpages.debian.org/bullseye/dash/dash.1.en.html) to look at $HOME/.profile:
pedz@Peace:s001 ~[S:hatred] % docker exec -it hatred-web-1 dash -i
# cat $HOME/.profile
PROOF=true; export PROOF
PATH=/hatred/bin:$PATH; export PATH
# env | sort
BUNDLE_APP_CONFIG=/usr/local/bundle
BUNDLE_SILENCE_ROOT_WARNING=1
GEM_HOME=/usr/local/bundle
HOME=/root
HOSTNAME=hatred
LANG=C.UTF-8
PATH=/usr/local/bundle/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
PWD=/hatred
RUBY_DOWNLOAD_SHA256=ca10d017f8a1b6d247556622c841fc56b90c03b1803f87198da1e4fd3ec3bf2a
RUBY_MAJOR=3.1
RUBY_VERSION=3.1.2
TERM=xterm
# ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 14:28 ? 00:00:01 puma 5.6.5 (tcp://0.0.0.0:3000) [hatred]
root 152 0 0 14:54 pts/0 00:00:00 dash -i
root 161 152 0 14:54 pts/0 00:00:00 ps -ef
# set
BUNDLE_APP_CONFIG='/usr/local/bundle'
BUNDLE_SILENCE_ROOT_WARNING='1'
GEM_HOME='/usr/local/bundle'
HOME='/root'
HOSTNAME='hatred'
IFS='
'
LANG='C.UTF-8'
OPTIND='1'
PATH='/usr/local/bundle/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'
PPID='0'
PS1='# '
PS2='> '
PS4='+ '
PWD='/hatred'
RUBY_DOWNLOAD_SHA256='ca10d017f8a1b6d247556622c841fc56b90c03b1803f87198da1e4fd3ec3bf2a'
RUBY_MAJOR='3.1'
RUBY_VERSION='3.1.2'
TERM='xterm'
_='-ef'
# lsb_release -c
Codename: bullseye
# cat /etc/os-release
PRETTY_NAME="Debian GNU/Linux 11 (bullseye)"
NAME="Debian GNU/Linux"
VERSION_ID="11"
VERSION="11 (bullseye)"
VERSION_CODENAME=bullseye
ID=debian
HOME_URL="https://www.debian.org/ "
SUPPORT_URL="https://www.debian.org/support "
BUG_REPORT_URL="https://bugs.debian.org/ "
#
Note that PROOF is not in env's output and PATH does not have /hatred/bin
prepended to it.
pedz
(173 rep)
Sep 23, 2022, 03:08 PM
• Last activity: Apr 13, 2023, 05:37 AM
1
votes
1
answers
250
views
dash script replace array
This script works if I use bash on my Debian 11 (bullseye). But now I need to refactor it to use Debian's `sh` shell(`/bin/dash`). #!/bin/dash var1=1 var2=2 var3=3 arr=($var1 $var2 $var3) exist_var="${arr[*]:+ message}" echo $exist_var Now, I get a message if any variable is set: tuy@debian$ bash sh...
This script works if I use bash on my Debian 11 (bullseye). But now I need to refactor it to use Debian's
sh
shell(/bin/dash
).
#!/bin/dash
var1=1
var2=2
var3=3
arr=($var1 $var2 $var3)
exist_var="${arr[*]:+ message}"
echo $exist_var
Now, I get a message if any variable is set:
tuy@debian$ bash sh_array.sh
message
And I get no message if a variable is not set:
tuy@debian$ bash sh_array.sh
$
###
I know dash does not support arrays. If any of the variables is defined, the script must print a message. If no variables are defined, this script must still work, but without printing a message.
tuytuy20
(115 rep)
Apr 9, 2023, 02:02 PM
• Last activity: Apr 9, 2023, 03:37 PM
7
votes
2
answers
1726
views
How do I keep a dash shell script running despite any error?
I have a dash shell script that is intended to run to the end of file: ``` #!/usr/bin/dash # File b_shell . a_nonexistent_file echo "I want to print this line despite any previous error." ``` However, it stopped running after failure to source a nonexistent file: ``` $ ./b_shell ./b_shell: 3: .: a_n...
I have a dash shell script that is intended to run to the end of file:
#!/usr/bin/dash
# File b_shell
. a_nonexistent_file
echo "I want to print this line despite any previous error."
However, it stopped running after failure to source a nonexistent file:
$ ./b_shell
./b_shell: 3: .: a_nonexistent_file: not found
I've tried candidate solutions including -e
and || true
, which can be easily found on the Internet, but to no avail.
Additional remarks:
1. I am not allowed to use other shells such as Bash, tcsh, etc. Please don't ask me to switch.
2. I noticed some other "Not Found" errors won't stop the script, as is illustrated below.
#!/usr/bin/dash
# File b_shell_ok
a_nonexistent_command
ls a_nonexistent_file
echo "This line is printed despite any previous error."
```
$ ./b_shell_ok
./b_shell_ok: 3: a_nonexistent_command: not found
ls: cannot access 'a_nonexistent_file': No such file or directory
This line is printed despite any previous error.
zanetu
(171 rep)
Mar 25, 2023, 06:09 AM
• Last activity: Mar 25, 2023, 12:09 PM
8
votes
2
answers
1213
views
Is there a pipefail equivalent for dash?
I have a perl script that runs a `system()` call to execute shell commands and I would like to run more than one command and pipe data between them. Something like (in perl): ```perl system("command1 | command2"); ``` Perl's `system()` uses `/bin/sh` and since these are running on an Ubuntu Server s...
I have a perl script that runs a
system()
call to execute shell commands and I would like to run more than one command and pipe data between them. Something like (in perl):
system("command1 | command2");
Perl's system()
uses /bin/sh
and since these are running on an Ubuntu Server system, /bin/sh
is dash
. Like many other shells, the exit value of a pipeline in dash is the exit value of the right-most command. This means that something like this will return 0
(success):
system("false | true")
If I were on a system whose /bin/sh
were bash
, I could fix it easily by adding the pipefail
option:
system("set -o pipefail; false | true");
Indeed, this works as expected on my local Arch system whose /bin/sh
points to bash
:
$ perl -le '$status = system("false | true"); print $status>>8'
0
$ perl -le '$status = system("set -o pipefail; false | true"); print $status>>8'
1
(Yes, I know this looks weird, but if you don't know Perl, just take my word for it: we need to shift by 8 to get the actual exit status)
However, since the machine it is supposed to run on has dash
, the same thing fails:
$ perl -le '$status = system("set -o pipefail; false | true"); print $status>>8'
sh: 1: set: Illegal option -o pipefail
2
Using set -e
is also not a solution:
$ perl -le '$status = system("set -e; false | true"); print $status>>8'
0
I can think of some Perl workarounds, such as not piping or using the IPC::System::Simple
module, but I was hoping there might be a simpler way to do this directly in dash.
So, is there some trick, hack or option that lets me tell dash
that the exit status of a set of piped commands should only be 0
(success) if _all_ commands worked and should be non-0 if any of them failed the way that set -o pipefail
works in bash
?
terdon
(251585 rep)
Jul 21, 2022, 05:30 PM
• Last activity: Feb 15, 2023, 12:17 PM
2
votes
1
answers
143
views
How to add a substring to a string as a column
The title may not be the best at describing the issue, but this was the best I could come up with, moving on to describe what I'm trying to do, I use artix runit as my os, and it is tedious to create a symlink for every service I want to enable, so I created this script to make it easier. ```bash #!...
The title may not be the best at describing the issue, but this was the best I could come up with, moving on to describe what I'm trying to do, I use artix runit as my os, and it is tedious to create a symlink for every service I want to enable, so I created this script to make it easier.
as you can see as service's names vary the location of the text at the end change which is not very appealing to the eye I would say, so I would like to ask if there's a solution to this, if there's none I guess I would add the
#!/bin/sh
rundir="/run/runit/service"
svdir="/etc/runit/sv"
for SERVICE in $(ls $svdir); do
[[ -d "$rundir/$SERVICE" ]] && output="$output$SERVICE linked: yes\n" || output="$output$SERVICE linked: no\n"
done
service=$(printf "$output" | dmenu -l 10) || exit 1
if printf "$service" | grep -Fqe "linked: yes"; then
service=$(printf "$service" | awk '{print $1}')
sudo -A rm "$rundir/$service"
else
service=$(printf "$service" | awk '{print $1}')
sudo -A ln -s "$svdir/$service" "$rundir/"
fi
Which checks all the services that can be enabled in /etc/runit/sv
and checks if they are already enabled by seeing if they exist in /run/runit/service
if it does it will add linked: yes
at the end of the dmenu list and if it doesn't, it adds linked: no
the problem is that the service's names vary so adding those things will result in this inconsistency:

linked: xxx
at the beginning since that would solve the problem, but it's my last resort.
And if anyone wants to point out a more efficient way to write the code please do, this is my first bash script and I have much to learn.
Note: I use dash as sh so i can't use any kind of bashisms.
Stagnant
(33 rep)
Feb 14, 2023, 09:01 PM
• Last activity: Feb 15, 2023, 12:14 AM
7
votes
1
answers
964
views
What parts of dash are not part of the POSIX standard?
I know that dash adheres quite closely to the POSIX standard, but I know that it's not 100.00% strict POSIX without any extras. The shell that comes closest/adheres exactly to the POSIX standard is as far as I know mrsh or yash with the POSIXly-correct flag set. Now I want to know exactly which part...
I know that dash adheres quite closely to the POSIX standard, but I know that it's not 100.00% strict POSIX without any extras. The shell that comes closest/adheres exactly to the POSIX standard is as far as I know mrsh or yash with the POSIXly-correct flag set.
Now I want to know exactly which parts/functionalities of dash are not specified in the POSIX standard (without reading the entirety of [POSIX.1-2017](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/contents.html) and the source code of dash).
I already tried extensive googling (as far as I'm knowledgable enough for this topic) but who would have thought, it's exclusively results on what the differences between bash and dash are and how dash is very POSIX compliant and so on.
cubernetes
(67 rep)
Mar 27, 2022, 03:05 PM
• Last activity: Jan 19, 2023, 01:01 PM
1
votes
1
answers
9760
views
dash: why am I getting the error "Syntax error: EOF in backquote substitution" when my script doesn't even contain a backquote?
#!/bin/sh -- for set_trap_sig in HUP INT QUIT ALRM TERM; do trap -- ' trap -- - '"${set_trap_sig:?}"' EXIT || exit "$?" kill -s '"${set_trap_sig:?}"' -- "$$" || exit "$?"' "$set_trap_sig" done sleep 15 || exit "$?" Here's what happens when I send SIGINT to the script user@hostname:/tmp$ ./script.sh...
#!/bin/sh --
for set_trap_sig in HUP INT QUIT ALRM TERM; do
trap -- '
trap -- - '"${set_trap_sig:?}"' EXIT || exit "$?"
kill -s '"${set_trap_sig:?}"' -- "$$" || exit "$?"' "$set_trap_sig"
done
sleep 15 || exit "$?"
Here's what happens when I send SIGINT to the script
user@hostname:/tmp$ ./script.sh
^C./script.sh: 3: ./script.sh: Syntax error: EOF in backquote substitution
This issue seems specific to dash. On ash, bash and ksh93 I do not get this error. This is particularly weird because my script does not even contain the backquote character.
If I remove the double quotes on the trailing
$?
on line 5 the error goes away.
Am I doing something stupid or is dash misbehaving? Please, no comments about the level of error-checking in my scripts.
We have now established that this a very serious bug that affects even modern versions of Ubuntu and Debian. Does anyone know of a workaround?
Harold Fischer
(1974 rep)
Apr 20, 2019, 06:17 AM
• Last activity: Dec 7, 2022, 08:26 PM
3
votes
1
answers
418
views
Why is "${1-"$var"}" (option 6 down below) not mentioned in POSIX?
The only reference I could find [in the spec is this][2]: > It would be desirable to include the statement "The characters from an enclosed "${" to the matching '}' shall not be affected by the double-quotes", similar to the one for "$()". However, historical practice in the System V shell prevents...
The only reference I could find in the spec is this :
> It would be desirable to include the statement "The characters from an enclosed "${" to the matching '}' shall not be affected by the double-quotes", similar to the one for "$()". However, historical practice in the System V shell prevents this.
The obvious question is: "what is that historical issue" and, more importantly, how does it affect us today ?
At the
C.2.5 Parameters and Variables
heading further down on that page there are a lot of examples of quoted expansions in what seems an exhaustive effort to list all of them, however, nowhere a twice double quoted example appear.
## Description
The issue is related to the outputs of this 6 alternatives of quoting:
- $b
, "$b"
, ${a-$b}
, ${a-"$b"}
"${a-$b}"
and "${a-"$b"}"
The first five are defined by POSIX and some shells agree on the result of such expansions. Note that some values get split on the value of $IFS
:
$ export a=abc; for sh in dash ksh93 bash; do $sh -c 'IFS="bl"; b=value
printf " " 1$b 2"$b" 3${a-$b} 4${a-"$b"} 5"${a-$b}" 6"${a-"$b"}";
echo'; done
However, is "${1-"$var"}"
defined somewhere in the spec ?
That is: with **repeated** double quotes, external and internal.
## Additional 1
Just as related information, look at this results: Note that the only difference of the previous code to this next code is that $a
is unset:
$ unset a; for sh in dash ksh93 bash; do $sh -c 'IFS="bl"; b=value
printf " " 1$b 2"$b" 3${a-$b} 4${a-"$b"} 5"${a-$b}" 6"${a-"$b"}";
echo'; done
## Additional 2
Common shells act in conflicting ways when actually testing all quoting options.
$ for sh in dash ksh93 bash; do $sh -c 'IFS="bl"; b=value
printf " " 1\n 2"\n" 3${a-\n} 4${a-"\n"} 5"${a-\n}" 6"${a-"\n"}";
echo'; done
And that is without including zsh!.
QuartzCristal
(2113 rep)
Oct 5, 2022, 01:12 PM
• Last activity: Nov 18, 2022, 11:06 AM
Showing page 1 of 20 total questions