I need to source 2 scripts in different locations and then run docker-compose but I am facing error that the scripts must be sourced first.
I found this How to use source command within Jenkins pipeline script question and wrote my jenkins commnad as below:
. ../env/scriptA.sh arg-1 ../env/scriptB.sh ../compose/build.yml arg-2
But still facing that error. So how I can source all these scripts and build file in the jenkins?
from bash manual
. (a period)
. filename [arguments]
Read and execute commands ...
the syntax is one filename and then positional parameters, it can't accept multiple files.
Concatenating files doesn't allow to change paramters between calls, maybe a command sequence could be used if allowed
{ . file1 args ; . file2 args;}
Note the space after the first opening brace and semicolon before closing brace are important.
As Nahuel Fouilleul mentioned in his answer this is just one line and the script and yml files are other arguments and as I mentioned in the comment to Nahuel Fouilleul the problem is because of "[[" I can't source that script in shell environment of jenkins (even if the script has its own shebang) so I added the shebang to the shell block in jenkins as below and now it works.
sh '''#!/bin/bash -xe
. ../env/scriptA.sh arg-1 ../env/scriptB.sh ../compose/build.yml arg-2
echo "other commands"
'''
Related
I have a Jenkins job in which I want to read a file from a directory using the shell and pass that file in ant test step.
Say the file I want to read is /home/xxx/y.txt. The name of the file always changes but there will be only single file with .txt extension at any given point in that directory.
So, I am trying to pass that file in the "Execute Shell" build action as ant -Dfile=/home/xxx/*.txt but the build is "unable to read the file".
The shell won't expand -Dfile=/home/xxx/*.txt into -Dfile=/home/xxx/y.txt because -Dfile=/home/xxx/y.txt is not a file. However, the shell will expand /home/xxx/*.txt into /home/xxx/y.txt. You can get the result you want using command substitution:
ant -Dfile=`echo /home/xxx/*.txt`
To protect against whitespace in the file path, you can use double quotes around the backticks:
ant -Dfile="`echo /home/xxx/*.txt`"
General tip: If you are having trouble with a shell script running in a Jenkins job, try enabling command tracing and view the console output to help debug. Command tracing can be enabled in one of two ways (take your pick):
Pass -x as an option to the shebang at the beginning of the script. For example, replace #!/bin/sh with #!/bin/sh -x. All commands will be output on standard error before they are executed.
Place set -x somewhere in your script. Commands after this line will be traced.
Consider:
set -- /home/xxx/*.txt
{ [ "$#" -eq 1 ] && [ -e "$1" ]; } || {
echo "ERROR: There should be exactly one file matching /home/xxx/*.txt" >&2
exit 1
}
ant -Dfile="$1"
This has several advantages:
You're actually detecting the unexpected cases instead of letting it passed unnoticed when (not if) an impossible thing happens.
Everything is happening in a single shell -- there's no subshell performance impact.
Your filenames aren't being mangled at all -- all the odd corner cases (ie. names with literal backslashes, which echo is allowed by POSIX to mangle) are fully supported.
It's fully compliant with any POSIX shell.
There's also a caveat:
set -- /home/xxx/*.txt overrides "$#", the argument vector, in the current context. If you need to refer to arguments as "$1", "$2", etc. in the outside script, you might put this code inside a function.
file_name=(`/home/xxx/*.txt`)
ant -Dfile=${file_name}
I have to create a script to setup an OpenVPN server automatically.
In this script I need to source the vars file in /etc/openvpn/easy-rsa/
But when I'm executing the following script in the /etc/openvpn/easy-rsa/ folder (with chmod 775 on the script and vars file) it says "xxxx.sh: 3: xxxx.sh: source: not found:"
#!/bin/bash
source ./vars
When I write . ./vars, it works, but then if I want to do a ./clean-all it says :
Please source the vars script first (i.e. "source ./vars")
Make sure you have edited it to reflect your configuration.
When I do the ./clean-all in the same script than the . ./vars, it works.
Thanks for your help (and sorry for my bad english :/)
When you source (or .) a file, all the commands inside it are read and executed - this includes variable assignments. However, when a variable assignment takes place, it takes place only for the current shell. When you run a script, a subshell is created - so any variables inside the script are only visible within the subshell, not the parent (calling) shell. This is why it works when you have run source and clean-all within the same script, it should also work if you do both from the command line, ie:
$ . /etc/openvpn/easy-rsa/vars
$ /etc/openvpn/easy-rsa/clean-all
I'm a newbie to scripting languages trying to learn bash programming.
I have very basic question. Suppose I want to create three folders like $HOME/folder/
with two child folders folder1 and folder2.
If I execute command in shell like
mkdir -p $HOME/folder/{folder1,folder2}
folder will be created along with child folder.
If the same thing is executed through script I'm not able get expected result. If sample.sh contains
#!/bin/sh
mkdir -p $HOME/folder/{folder1,folder2}
and I execute sh ./sample.sh, the first folder will be created then in that a single {folder1,folder2} directory is created. The separate child folders are not created.
My query is
How the script file works when we compared to as terminal command? i.e., why is it not the same?
How to make it work?
bash behaves differently when invoked as sh, to more closely mimic the POSIX standard. One of the things that changes is that brace expansion (which is absent from POSIX) is no longer recognized. You have several options:
Run your script using bash ./sample.sh. This ignores the hashbang and explicitly uses bash to run the script.
Change the hashbang to read #!/bin/bash, which allows you to run the script by itself (assuming you set its execute bit with chmod +x sample.sh).
Note that running it as sh ./sample.sh would still fail, since the hashbang is only used when running the file itself as the executable.
Don't use brace expansion in your script. You could still use as a longer method for avoiding duplicate code:
for d in folder1 folder2; do
mkdir -p "$HOME/folder/$d"
done
Brace expansion doesn't happen in sh.
In sh:
$ echo {1,2}
produces
{1,2}
In bash:
$ echo {1,2}
produces
1 2
Execute your script using bash instead of using sh and you should see expected results.
This is probably happening because while your tags indicate you think you are using Bash, you may not be. This is because of the very first line:
#/bin/sh
That says "use the system default shell." That may not be bash. Try this instead:
#!/usr/bin/env bash
Oh, and note that you were missing the ! after #. I'm not sure if that's just a copy-paste error here, but you need the !.
There are two options to run a shell script:
$ ./some/script.sh
$ . ./some/script.sh
As far as I unterstand, the first one starts a new shell environment based on the given shebang line withing the script. While the second one executes the statements within the same shell environemnt.
Are there more differences ?
Where can I find more documentation about the second one ?
Is . a real command ? I can not find a manpage to it.
Are there more differences ?
The gist of the matter is that using . the script is executed line by line in the same process. Otherwise a new process is forked. And a separate process has no way of changing the parent, for example it can't change environment variables such as the current directory.
Where can I find more documentation about the second one ?
[cnicutar#fresh ~]$ help source
source: source filename [arguments]
...
Is . a real command
[cnicutar#fresh ~]$ type .
. is a shell builtin
In case it isn't obvious already, . and source are identical*.
As rush commented, source isn't specified by POSIX so you should probably use . in code intended to be portable. The dot is specified in chapter 2.
. is a Bourne Shell command for reading a file and executing the commands in the file, your analysis is essentially correct. bash and other shells add source as an alias for ..
See the manual for bash builtins, and see . at the top of the manual for Bourne sh builtins.
Read and execute commands from the filename argument in the current shell context. If filename does not contain a slash, the PATH variable is used to find filename. When Bash is not in posix mode, the current directory is searched if filename is not found in $PATH. If any arguments are supplied, they become the positional parameters when filename is executed. Otherwise the positional parameters are unchanged. The return status is the exit status of the last command executed, or zero if no commands are executed. If filename is not found, or cannot be read, the return status is non-zero. This builtin is equivalent to source.
it is used to source an environment. such as the .profile.
This question already has answers here:
Why can't I change directories using "cd" in a script?
(33 answers)
Closed 4 years ago.
I 'm wondering of any mechanism that one could use to change the directory of a parent shell from sub-shell. For ex., I 'm running the script "settings.sh" in my $HOME. My $HOME has a directory $HOME/TEST/run. If my "settings.sh" scripts is as below
#!/bin/bash
# some shell related code
# some shell related code
cd $HOME/TEST/run
exit 0
I execute the above script at command prompt at $HOME. After the execution, I expect my command prompt in directory $HOME/TEST/run. I do understand that in sub-shell, it is being cd'd to $HOME/TEST/run, but at the end of the execution, it's back in $HOME.
Is there any elegant way of doing the above, using a single script. One way is to modify the script "settings.sh" to generate another script and then use ". $HOME/generatedScript.sh"
Nope, you can't. That's by design. Parent processes should never be affected by the results of a child without them wanting to be affected (otherwise sub-shells could do all sorts of nasty tricky things to the parent).
What you can do is have the shell save the information into a file or print the directory or ... Such that the parent at least can use it to change directories if the parent wants to.
Wes Hardaker explained the reasoning behind why executing that script does not cause it to change the directory of the parent shell. In order to work around that type of issue, you must "souce" the script instead of execute it. This causes the commands in the script to run in the current shell, rather than a child process.
. ./settings.sh
The first "." is a command which tells the shell to "source" the specified file. Here is the documentation from help .:
.: . filename [arguments]
Execute commands from a file in the current shell.
Read and execute commands from FILENAME in the current shell. The
entries in $PATH are used to find the directory containing FILENAME.
If any ARGUMENTS are supplied, they become the positional parameters
when FILENAME is executed.
Exit Status:
Returns the status of the last command executed in FILENAME; fails if
FILENAME cannot be read.