Can substring expansion be used in dash shell or bourne shell? - linux

I'm converting an app to a new image, and the existing commands use substring expansion to set the artifact version like so: mvn clean versions:set -DnewVersion="0.1.$VCSINFO.I${INFO:0:6}.M$OTHER_INFO". I'm using a ubuntu image that defaults to /bin/sh, and I am unable to figure out how to either do something equivalent in bourne shell, or switch shells to run the command. I know bash is installed because I can see it in /etc/shells.
I tried using RUN ['/bin/bash', '-c', '...'] but I can see it is just running that command like so The command '/bin/sh -c ['/bin/bash', '-c',.... What is the best way to convert this functionality over to this new image?

You can run a bash command in two ways, even from sh: Either by passing the string '/bin/bash path/to/your/cmd' to the -c option of sh, or by setting the x-bit in cmd and having as the first line in cmd a #!/bin/bash.
Hence in your setting I would try either a RUN ['/bin/bash /path/to/your/cmd'] or just do a RUN ['/path/to/your/cmd'] and ensure that cmd has the #! line mentioned above, or complicated but fail safe - write a sh wrapper script, which then invokes the bash script in turn. Hence, if this wrappe script is called /path/to/your/cmdwrapper.sh, its content would be
:
/bin/bash /path/to/your/cmd

Related

Cannot make bash script work from cloud-init

Obviously I am doing something wrong here.
Cloud init script /etc/cloud/cloud.cfg
...
runcmd:
- [ sh, /opt/cloud-init-scripts/whatever.sh ]
The script /opt/cloud-init-scripts/whatever.sh
#!/bin/bash
...
. /home/ubuntu/third-party/script.sh --silent
Third party script /home/ubuntu/third-party/script.sh
#!/usr/bin/env bash
function some_function() {
...
Error I am getting in /var/log/cloud-init-output.log
/opt/cloud-init-scripts/whatever.sh: 3: /home/ubuntu/third-party/script.sh: Syntax error: "(" unexpected
I must be missing something obvious here. I tried using source, . and sh when calling the third party script, tried changing shebangs everywhere but no success.
If I run the same command from command line it works.
You have specified sh shell under runcmd, but have she-bang set to bash. The latter does not matter because if you run as sh /opt/cloud-init-scripts/whatever.sh it will be run with sh shell. I guess you are probably using a non POSIX shell feature which is incompatible with the sh shell.
Or alternatively if your intention is to run the script in bash shell, change the runCmd in cloud-init script to
runcmd:
- [ bash, /opt/cloud-init-scripts/whatever.sh ]

Execution error in a makefile

This is a reduced example of a makefile which illustrates my problem:
exec:
time (ls > ls.txt; echo $$? > code) 2> time.txt
make exec runs fine under one Linux installation:
Linux-2.6.32-642.4.2.el6.x86_64-x86_64-with-centos-6.8-Final
but it fails under my Ubuntu installation:
Linux-4.4.0-64-generic-x86_64-with-Ubuntu-16.04-xenial
and produces the message:
/bin/sh: 1: Syntax error: word unexpected (expecting ")")
No problems if I run the command time directly from the terminal.
Are there different versions of the command in different Linux installations? I need the version which allows a sequence of commands.
Make always invokes /bin/sh to run the recipe. On some systems, /bin/sh is an alias for bash which has a lot of extra extensions to the standard POSIX shell (sh). On other systems (like Ubuntu), /bin/sh is an alias for dash which is a smaller, simpler, closer to plain POSIX shell.
Bash has a built-in time operation which accepts an entire pipeline and shows the time taken for it (run help time at a bash shell command prompt to see documentation). Other shells like dash don't have a built-in time, so when you run it you get the program /usr/bin/time; run man time to see documentation. As a separate program it of course cannot time an entire pipeline (because a pipeline is a feature of the shell); it can only time one individual command.
You have various options:
You can force your makefile to always use bash as its shell by adding:
SHELL := /bin/bash
to it. I recommend adding a comment there as well describing why bash specifically is needed.
Or you can modify your rule to work in a portable way by making the shell invocation explicit so that time only has one command to invoke:
exec:
time /bin/sh -c 'ls > ls.txt; echo $$? > code' 2>/time.txt
Put a semicolon in front of "time". As is, make is trying to parse your command as a list of dependencies.
The only suggestion that worked is to force bash in my makefile:
SHELL := /bin/bash
I checked: on my Ubuntu machine, /bin/sh is really /bin/dash whereas on the CentOS machine it is /bin/bash!
Thanks!

Can make shell run interactively along with --command option

I'm using GNU bash that is installed as git bash. On startup I need to change directory, so I'm doing it like this:
"C:\Program Files\Git\bin\sh.exe" --rcfile "./cd.sh"
Where cd.sh just contains cd /d/ command. Everything works fine here. Now I'm trying to get rid of cd.sh file and pass command to the shell as a parameter yet I want it to remain interactive, so I'm doing like this:
"C:\Program Files\Git\bin\sh.exe" -ic "cd /d"
It executes the command (tested with echo command) but then exits. Why doesn't it stay interactive?
From man bash:
An interactive shell is one started without non-option arguments and without the -c option ...
From man dash:
If no args are present and if the standard input of the shell is connected to a terminal (or if the -i flag is set), and the -c option is not present, the shell is considered an interactive shell.

curl - Issue with special character URL running inside shell script

when running curl command on the command line, putting quotes around url with '&' works, but when running inside a shell script, its not working as expected.
curl -Lks -o /dev/null -w "%{url_effective}\n" "https://www.XXXX.com?ver=test1&ver1=test2"
Probably, you're using a different shell to interactively run that command then you specify as the shell that should execute the file.
Try executing
echo $SHELL
If you want to have the same semantics, that same shell must be used as the so-called Shebang executor.

What is the difference between `./example.sh` and `sh example.sh`

I am trying to play with bash and arrays. But executing a sample script, I got an unexpected syntax error message: example.sh: 3: example.sh: Syntax error: "(" unexpected. And this is the script
#!/bin/bash
array=( one two three )
If I run the script with ./example.sh it works and no errors are displayed. But if I run sh example.sh I get the error message.
I thought that these two commands are the same:
sh example.sh
./example.sh
so ... what is the difference between the two?
When you launch it via ./example.sh then the command specified in the first line of the script is used to interpret the content. So your script executes in a bash, where such syntax is allowed for arrays.
When you launch it via sh example.sh then sh is the command that is used to interpret the content of the file. sh is the original Unix shell (aka Bourne shell) and this shell is a little more rude than bash (Bourne again shell). You don't have such arrays. Note that in sh the first line of your script is just interpreted as a comment.
by using sh example.sh
- you are specifying what shell interpreter to use for that script. Example being "bash example.sh" instead of "sh example.sh" etc etc.
Running scripts this way disregards the "shebang (#!/bin/bash)" that you have specified inside of the script. Since you wrote a bash script but are trying to run it as just "sh", this is why it is failing
by using ./example.sh,
- You are specifying to run the script from your current directory. This will attempt to run the script in whatever shell you are currently in unless a shebang is specified. Since you have a "shebang" specified to run the script in bash... this is why it is working.
array_name=(value1 ... valuen)
This is how to initializes an array in bash only. When you execute ./example.sh, the shebang line #!/bin/bash tells the system to use bash to execute.
However, when you execute sh example.sh, sh is used to execute. In many Unix systems (like Linux), sh is equivalent to bash. It seems sh is a different shell on your system.

Resources