shebang under linux does not split arguments - linux

I have kotlin script (but it can be any Linux command with arguments) for example:
#!/usr/bin/env kotlinc -script
println("hello world")
When I run it in Ubuntu I get:
/usr/bin/env: ‘kotlinc -script’: No such file or directory
but when I run in command line:
/usr/bin/env kotlinc -script
It works. It is no problem with finding path because script:
#!/usr/bin/env kotlinc
println("hello world")
works
For some reason under Ubuntu "#!/usr/bin/env kotlinc -script" treats "kotlinc -script" as single argument. But only in shell script header.
I need explicitly to run my script "#!/usr/bin/env kotlinc -script" because I want it to run properly on other distributions end environments where "kotlin" is in $PATH.
Is there a bug in Ubuntu coreutils or sth? Is there a way to fix it?

On Linux, you can't pass more than one argument via the shebang line. All arguments will be passed as a single string to the executable:
#!/bin/foo -a -b -c
will pass one option "-a -b -c" to /bin/foo, plus the contents of the file. Like if you would call:
/bin/foo '-a -b -c' contents-of-file.txt
The behaviour should be the same on most unix derivates nowadays, but it can differ, I haven't tested them all :)
It's hard to find proper documentation for this, the best I could quickly find was this: https://www.in-ulm.de/~mascheck/various/shebang/#splitting
As a workaround you would normally create a shell wrapper:
#!/bin/bash
exec kotlin --arg1 --arg2 ... /path/to/kotlin-script

Check your coreutils version:
apt-cache policy coreutils
Starting with coreutils 8.30 you will be able to use:
#!/usr/bin/env -S command arg1 arg2 ...
You may want to upgrade your coreutils

For me the solution was to install kotlin, since I did not yet have installed it and just downloaded https://github.com/bernaferrari/GradleKotlinConverter
and thought it should work.
sudo snap install kotlin --classic

Related

Show bash directory from command prompt windows

I am working in WSL Ubuntu
When i execute command directly, show wrong path
C:\Users\Administrator>bash -c 'pwd'
/
Expected output :
C:\Users\Administrator>bash -c 'pwd'
/mnt/c/Users/Administrator/
How to fix this
I'm not able to reproduce this on any of my systems. Is it possible that you have a cd / (or equivalent) somewhere in one of your startup scripts?
First, let's change that to use wsl.exe command in place of the deprecated bash.exe command:
wsl pwd
That should give you the same (wrong) result that you are already seeing, but let's confirm that.
Then, to start WSL and tell Bash to not execute your startup scripts, try:
wsl -e bash --noprofile --norc -c pwd
Then try the shorter:
wsl -e pwd
The -e/--exec argument tells WSL to run the command in place of the shell, so Bash (and its startup files) should never get called in the first place.

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

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

How to execute lua bytecode genrated by luac on linux

I have a simple lua source code called hello.lua
print('Hello Lua')
I complied this file to bytecode on a RedHat Linux machine , using Lua5.3.4 as follows:
luac -o hello.luac hello.lua
chmod +x hello.luac
./hello.luac
bash: ./hello.luac: cannot execute binary file
The architecture should be fine I guess. I cant figure what is wrong.
Precompiled Lua programs are run exactly the same way as source:
lua hello.luac
The shebang is removed by luac even if the lua source file has it. In some case when it's necessary to run the compiled binary without any parameter, e.g. CGI, you can add the shebang manually at the top of the luac file:
luac -o hello.luac hello.lua
echo '#!/usr/bin/env lua' > shebang
cat shebang hello.luac > hello.luac2
mv hello.luac2 hello.luac
chmod +x hello.luac
./hello.luac
As #lhf states in his answer Lua byte code is executed using the Lua interpreter, and as the manual suggests:
To allow the use of Lua as a script interpreter in Unix systems, the standalone interpreter skips the first line of a chunk if it starts with #. Therefore, Lua scripts can be made into executable programs by using chmod +x and the #! form.
Add a shebang as the first line of your script:
#!/usr/bin/env lua
print('Hello Lua')

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!

perl + perl script location under /etc/rc3.d with diff results

I need advice about the following:
option 1
I run the script /usr/local/bbp/api/bbpinstaller.pl from /var/tmp directory in my Linux machine and there are no problem
option 2
I create new script - script.pl under /var/tmp
and then I create link from /var/tmp/script.pl to /etc/rc3.d/S99script.pl ( by ln -s )
so S99script.pl is link to /var/tmp/script.pl
and script.pl execute the /usr/local/bbp/api/bbpinstaller.pl
more /etc/rc3.d/script.pl
#!/bin/bash
/usr/local/bbp/api/bbpinstaller.pl
.
.
.
my problem :
when the script bbpinstaller.pl run after reboot from /etc/rc3.d/S99script.pl then I get the following errors ( /usr/local/bbp/api/bbpinstaller.pl run from S99script.pl )
Can't locate Term/ReadKey.pm in #INC (#INC contains: /etc/bbp/shared /usr/perl5/5.8.4/lib/sun4-solaris- 64int /usr/perl5/5.8.4/lib /usr/perl5/site_perl/5.8.4/sun4-
solaris- 64int /usr/perl5/site_perl/5.8.4 /usr/perl5/site_perl /usr/perl5/vendor_perl/5.8.4/sun4- solaris-64int /usr/perl5/vendor_perl/5.8.4 /usr/perl5/vendor_perl
. ) at /usr/local/bbp/api/bbpinstaller.pl line 25.
BEGIN failed--compilation aborted at /usr/local/bbp/api/bbpinstaller.pl line 25.
in /usr/local/bbp/api/bbpinstaller.pl script , I have the following perl modules:
#################################
# Modules imported
#################################
use Config;
use Getopt::Long;
use File::Find;
use English;
use Sys::Hostname;
$File::Find::dont_use_nlink=1;
use lib "/etc/bbp/shared";
use Term::ReadKey qw(GetTerminalSize);
use Cwd 'abs_path';
require "bbp_globals.pl";
require "bbp_functions.pl";
the PATH of the file ReadKey.pm
/usr/local/lib/perl5/site_perl/5.8.7/sun4-solaris-thread-multi/Term/ReadKey.pm
please help me to understand . what the problem here ??? ( I not have allot experience with Perl )
/usr/local/ is used by local installs (i.e. it wasn't provided by the OS vendor). Then your shell is setup to run ($PATH) /usr/local/bin/perl (5.8.7) rather than /usr/local/bin/perl (5.8.4).
However the init scripts don't run with your shell settings - they use the system settings, which won't have /usr/local/bin in them - so they will use the OS provided perl - /usr/bin/perl which doesn't have this library (Term::ReadKey) installed.
(The .pl extension is normally for perl programs - I'd use .sh for bash/shell scripts)
When you run a script directly (that is, not specifying an interpreter first on the command-line), the kernel uses the hash-bang line (the first line) to work out which program to execute to interpret the script.
e.g. your shell script /etc/rc3.d/script.pl has a hash bang line of "#!/bin/bash", telling it to execute with /bin/bash.
/usr/local/bbp/api/bbpinstaller.pl will have a hash-bang line at its start, possibly something like: #!/usr/bin/env perl
This tells the kernel/shell to look at the PATH variable to find an interpreter; the same way it would find perl if you typed it on the command-line.
In order to fix your problem, either:
Install Term/ReadKey into the system perl.
Set your PATH in you shell script as MichaelN suggests.
Call the explicit perl instead of letting the kernel decide, as MichaelN also suggests.
Recode /usr/local/bbp/api/bbpinstaller.pl to not need Term/ReadKey
By default the os perl is /usr/bin/perl which has all its modules in /usr/perl5/site_perl/5.8.4 /usr/perl5/site_perl. Since running the script via rc3 uses root's standard path and standard lib, it won't find your custom perl in /usr/local/bin and thus won't find your site-lib in /usr/local/lib. So you need to modify your calling script "/etc/rc3.d/script.pl" which is a bash script (should probably be call script.sh but that's symantics) to include /usr/local/bin in the path, ie: export PATH=/usr/local/bin:${PATH}. That'll pre-append the /usr/local/bin to the front of the PATH and then your perl in /usr/local/bin will be called instead of /usr/bin/perl. So change the script.pl to:
#!/bin/bash
export PATH=/usr/local/bin:${PATH}
/usr/local/bbp/api/bbpinstaller.pl
or call your script with your perl.
#!/bin/bash
/usr/local/bin/perl /usr/local/bbp/api/bbpinstaller.pl
I'm totally keying off the work Douglas did in analyzing your issue, in order to provide the fix you asked for.
I would either:
In the RC shell script, set your PATH to run the right version of perl, and then call your Perl script.
Change the "shebang" line in your Perl script to use the right version of Perl.
Hope one of those helps!

Resources