Cannot figure this one our or create a sample which can reproduce this.
Am trying using an external sh file to invoke the hadoop sh file
myfile.sh
# workingdir = /data1/some/path/lib
WORKINGDIR=`cygpath -p -w -m "$WORKINGDIR"`
# so the above in windows land is C:/some/path/lib
# HADOOPCMD essentially is a call to hadoop.sh
$HADOOPCMD jar $WORKINGDIR/myjar.jar
hadoop.sh
echo "$#" // still C:/some/path/lib
exec "$JAVA" $JAVA_HEAP_MAX $HADOOP_OPTS $CLASS "$#"
However when "$#" is expanded in cygwin the resultant path becomes C:\some\path\lib and then the hadoop.sh complaints that it cannot find the jar ... Not a valid JAR : C:\some\path\lib
However if I were to hardcode the path in myfile.sh ; it works
$HADOOPCMD jar C:/some/path/lib/myjar.jar
Question
why does the exec command's "$#" change the / to \ in the WORKINGDIR variable ?
why does the hardcoded path work ?
how to get this to work with variable substituion ?
Quoting the variable works "$WORKINGDIR"/myjar.jar
Related
I am creating a Dockerfile which starts a Java application. This Java application is given a file path which contains the output of ls -l.
(Note that in my real Dockerfile I am not doing ls - l but rather complex commands. I altered that to ls - l to simplify the question.)
I tried the following:
FROM openjdk:8-jre
ARG JAR
COPY target/$JAR /app/app.jar
CMD java -jar /app/app.jar <( ls -l )
This bash <( ... ) construction should create a temporary file containing the output of ls -l.
When starting the Docker file, I get:
/bin/sh: 1: Syntax error: "(" unexpected
Now, sh does not support the <( ... ) construction, hence the error. How can I start the application safely via bash instead of sh? With safely I mean that the Java app still will receive all OS signals (SIGHUP, ...) and react appropriately.
Replace your command with a JSON list, for which the first two elements are bash -c, and the last element is the shell command you actually want to run.
CMD ["bash", "-c", "exec java -jar /app/app.jar <( ls -l )"]
To generate such an array for a more complex command, you might consider using jq to ensure that syntax is correct, even for input with backslashes, newlines or quotes:
jq -cnRs '["bash", "-c", input]' <<'EOF'
# you can put other shell commands here if you need to
exec java -jar /app/app.jar <( ls -l )
EOF
exec ensures that the java instance replaces bash, and thus is sent signals directly.
If you're doing complex things on startup it's often easier to write them into a script than try to build a very complicated command line. Once you're doing that, you can use the set of primitives that are available in the POSIX shell standard, even if they require multiple commands to do things that GNU bash could do inline.
For this I might write a script:
#!/bin/sh
ls -l >/ls-l.txt
exec java -jar /app/app.jar /ls-l.txt
and then copy it in as the default thing your image runs
FROM openjdk:8-jre
ARG JAR
COPY target/$JAR /app/app.jar
COPY launch-app.sh /usr/bin/app
# RUN chmod +x /usr/bin/app, if it's not already executable
CMD ["app"]
this is part of my current code
#! /bin/bash
#Take no arguments in
#checks to see if home/deleted is in existence
#creates the directory or file if it is missing
**(line 15)** function checkbin(){
if [ ! -c "~/deleted" ]; then
mkdir -p ~/deleted
fi
if [ ! -f "~/.restore.info" ]; then
touch ~/deleted/.restore.info
fi
}
I can call this code properly using ./remove [ARGS]
however when I call using sh remove [ARGS]
I receive the following error remove: 15: remove: Syntax error: "(" unexpected
ls -l on the file -rwxr-x--x
Does unix support execution on both sh and ./ ?
when executing with ./ /bin/bash is used (as define in shebang) whereas sh may be another interpreter or a link to bash which can have a different behaviour depending on how it is called sh.
bash is derived from sh but has some specific syntax:
for example in sh Function Definition Command is
fname() compound-command[io-redirect ...]
without function keyword.
For more details
Bash
Posix shell
If you want your script to run in sh as well as in bash, you need to be writing to the POSIX shell standard.
In this case, that means not using the Bash function keyword:
checkbin(){
test -c "~/deleted" || mkdir -p ~/deleted
test -f "~/.restore.info" || touch ~/deleted/.restore.info
}
If you're writing portable shell, then it's a good idea to use #!/bin/sh as your shebang.
(BTW, I assume you're aware that "~/deleted" and ~/deleted are in no way alike?)
I am using Cygwin Terminal to run shell to execute shell scripts of my Windows 7 system.
I am creating directory , but it is getting created with a dot in name.
test.sh
#!/bin/bash
echo "Hello World"
temp=$(date '+%d%m%Y')
dirName="Test_$temp"
dirPath=/cygdrive/c/MyFolder/"$dirName"
echo "$dirName"
echo "$dirPath"
mkdir -m 777 $dirPath
on executing sh test.sh its creating folder as Test_26062015 while expectation is Test_26062015.Why are these 3 special charterers coming , how can I correct it
Double quote the $dirPath in the last command and add -p to ignore mkdir failures when the directory already exists: mkdir -m 777 -p "$dirPath". Besides this, take care when combining variables and strings: dirName="Test_${temp}" looks better than dirName="Test_$temp".
Also, use this for static analysis of your scripts.
UPDATE: By analyzing the debug output of sh -x, the issue appeared due to DOS-style line-endings in the OP's script. Converting the file to UNIX format solved the problem.
The following code checks if you have root authority, then runs the script again with it :
CMDLN_ARGS="$#" # Command line arguments for this script (if any)
export CMDLN_ARGS
func_check_for_sudo() {
if [ ! $( id -u ) -eq 0 ]; then
echo "You may be asked for your login password for [`whoami`]." ;sleep 1
LAUNCH="`dirname \"${0}\"`"
exec sudo -S su -c ${LAUNCH}/$(basename ${0}) ${CMDLN_ARGS}
exit ${?}
fi
}
Where things are going wrong is when I place this script in a "$HOME/bin" folder or something so I can just launch it without the path. It gives me the error "No such file or directory". I need the script to get that information and correctly pass it to exec.
My question is this: how do I get the /path/to/script_name from within a script correctly when it is called without the path? To recap, I'm calling MY_SCRIPT insead /path/to/MY_SCRIPT which breaks my script because it has to check for root authority and run again if you don't have it.
Basically the line of code in question is this where ${0} is the script name (with path if you called it with one):
exec sudo -S su -c ${0} ${CMDLN_ARGS}
There are a couple of problems here:
Finding the path to the script. There are a couple of easy ways to do this: use "$BASH_SOURCE" instead of $0; or simply take advantage of the fact that (at least by default), sudo preserves $PATH, so sudo "$0" ... will resolve the script fine.
The second is that the script doesn't preserve its arguments properly. Spaces within arguments will be mistaken for breaks between arguments, and wildcards will be erroneously expanded. This is because CMDLN_ARGS="$#" mushes all the arguments together separated by spaces, and then ${CMDLN_ARGS} re-splits on spaces (maybe not the same way) and also expands wildcards.
Here's my take at correcting the problems. Note that putting the handler in a function just adds a layer of unnecessary complication, so I just put it inline. I also used sudo's -p option to clean up the prompting slightly.
if [ $( id -u ) -ne 0 ]; then
exec sudo -p "Login password for %p: " "$0" "$#"
exit $?
fi
I have a folder organization that looks like this:
link.sh
dist/MyApp-3.0.0/script.sh
dist/MyApp-3.0.0/lib/*.jar
The link.sh is a symbolic link to the KornShell (ksh) script script.sh. In the shell script, I want to call a Java program with following command:
java -cp lib/*
When I try to launch the application from the symbolic link, I get ClassNotFound because the relative path is resolved from the link base dir (this is normal).
Inside the shell script, how can I get the full path of the script (<...>/dist/MyApp-3.0.0/)? It will allow me to modify my Java call:
java -cp ${SCRIPT_DIR}/lib/*
Edit: using readlink
You can use readlink, and it boils down to:
SCRIPT_DIR=$(dirname "$(readlink -f $0)")
Edit: without readlink
if test -h $0; then
symdir=$(dirname "$(ls -l $0 | sed -n 's/.*-> //p')")
if [[ -z $symdir ]]; then
symdir=.
fi
fullreldir=$(dirname $0)/$symdir
fi
script_dir=$(cd $fullreldir; /bin/pwd)
I misunderstood the location of the script, and had assumed that the directory of the script being invoked was in the directory structure of the target application, where the following would work:
SCRIPT_DIR=$(cd $(dirname $0); /bin/pwd)
You have to use the readlink function (man readlink)
my2c