from csh to bash and re-source the same file - bash

I have a bash file that needs to get sourced. Users might have a csh without knowing (default configuration) so I wanted to change the shell to bash but sourced the file as that was the user's intention.
There are a lot of help around this and the resulting code would be:
#!/bin/csh (AND bash!)
[ "$?shell" = "1" ] && bash --login -c 'source this_file; bash' && exit
...
Everything works as expected besides the fact that the sourced file this_file must be hard-coded. In csh $_ would contain source this_file as that was the command that started sourcing the script, but there is no way I can pass it to the bash command.
This means:
If I use:
... && set this_file=($_) && bash -c "$this_file; bash" && ...
bash will complain that the parenthesis are wrong (this happens the second time as bash is started and tries to source this_file
If I use:
... && bash -c ""$_"; bash" && ...
bash gets a broken command that doesn't work either: bash -c "source" "this_file" "; bash"
If I use:
... && bash --login -c "$_; bash" && ...
csh gets a broken command: `Unmatched ".
I can't find out how to use $_ with an accepted bash syntax that passes the value as a single command (i.e. bash -c "source this_file; bash")
This is the test:
cat >a.sh<<'EOF'
[ "$?shell" = "1" ] && bash --login -c 'source a.sh; bash' && exit
a=1
EOF
And then I expect this to work:
$ csh -c 'source a.csh'
$ echo $a
1
I'm pretty sure it used to work... I'm trying to find out why it doesn't now. (I solved this problem using the tcl modules package, but I'll give this a try)

It is possible to pass arguments to a bash -c 'cmd' construct, i. e. bash -c 'echo $#' arg0 1 2 3 4 5!
#!/bin/csh (AND bash!)
#[ "$?shell" = "1" ] && bash --login -c 'source this_file; bash' && exit
[ "$?shell" = "1" ] && bash --login -c '${#}; bash' arg0 $_ && exit

Related

nesting if in a for loop for aws cli commands [duplicate]

I am trying to compare strings in bash. I already found an answer on how to do it on stackoverflow. In script I am trying, I am using the code submitted by Adam in the mentioned question:
#!/bin/bash
string='My string';
if [[ "$string" == *My* ]]
then
echo "It's there!";
fi
needle='y s'
if [[ "$string" == *"$needle"* ]]; then
echo "haystack '$string' contains needle '$needle'"
fi
I also tried approach from ubuntuforums that you can find in 2nd post
if [[ $var =~ regexp ]]; then
#do something
fi
In both cases I receive error:
[[: not found
What am I doing wrong?
[[ is a bash-builtin. Your /bin/bash doesn't seem to be an actual bash.
From a comment:
Add #!/bin/bash at the top of file
How you are running your script?
If you did with
$ sh myscript
you should try:
$ bash myscript
or, if the script is executable:
$ ./myscript
sh and bash are two different shells. While in the first case you are passing your script as an argument to the sh interpreter, in the second case you decide on the very first line which interpreter will be used.
Is the first line in your script:
#!/bin/bash
or
#!/bin/sh
the sh shell produces this error messages, not bash
As #Ansgar mentioned, [[ is a bashism, ie built into Bash and not available for other shells. If you want your script to be portable, use [. Comparisons will also need a different syntax: change == to =.
if [ $MYVAR = "myvalue" ]; then
echo "true"
else
echo "false"
fi
I had this problem when installing Heroku Toolbelt
This is how I solved the problem
$ ls -l /bin/sh
lrwxrwxrwx 1 root root 4 ago 15 2012 /bin/sh -> dash
As you can see, /bin/sh is a link to "dash" (not bash), and [[ is bash syntactic sugarness. So I just replaced the link to /bin/bash. Careful using rm like this in your system!
$ sudo rm /bin/sh
$ sudo ln -s /bin/bash /bin/sh
If you know you're on bash, and still get this error, make sure you write the if with spaces.
[[1==1]] # This outputs error
[[ 1==1 ]] # OK
Specify bash instead of sh when running the script. I personally noticed they are different under ubuntu 12.10:
bash script.sh arg0 ... argn
Execute in your terminal:
sudo update-alternatives --install /bin/sh sh /bin/bash 100
Make the file executable and then execute without sh.
make it executable by $ chmod +x filename
then instead of sh filename use ./filename

Is there any difference between "sh -c 'some comand'" and directly run some command

let's say echo command, we can run that command by two ways:
# by 1
echo 'hello'
# or by 2
sh -c "echo 'hello'"
Is there any difference between the two ways? By the way, I can see the way 2 is very popular in yaml config files.
- name: init-mydb
image: busybox:1.28
command: ['sh', '-c', "sleep 2; done"]
The first way calls an inherited command interpreter, eg from a terminal running /bin/bash ; the second way exec sh (aka Bourne Shell) as the interpreter and instruct him ( -c ) to do something.
sh, ksh, csh, bash are all shell interpreters. They provide some features that are not always compatible between them. So, if you don't know the environment where your program will run, the best is to specify the interpreter you want, which is less error prone.
This is a single command:
foo 1 2 3
So is this
sh -c 'foo 1 2 3'
This is not a single command (but rather a pair of commands separated by a ;)
foo; bar
but this is
sh -c "foo; bar"
This does not specify a command using the name of a executable file
for x in 1 2 3; do echo "$x"; done
but this does
sh -c 'for x in 1 2 3; do echo "$x"; done'
sh -c is basically way to specify an arbitrary shell script as a single argument to a command that can be executed from a file.

Why are my variables not being respected in this ZSH script [duplicate]

This question already has answers here:
Why does a space in a variable assignment give an error in Bash? [duplicate]
(3 answers)
Assigning to a positional parameter [duplicate]
(3 answers)
How do I pass arbitrary arguments to a command executed over SSH? [duplicate]
(1 answer)
Closed 1 year ago.
I have this shell script where I want the CLI inputs to be fed into the SSH command. The first SSH command runs as expected whereas the second has runTests.sh's $1 and $2 set to ''. It seems like it is not substituting them in. Any insights on why that might be?
$1=7107
$2=development
ssh redacted#redacted -t 'zsh -l -c "source ~/.zshrc && ./runTests.sh 7107 development"'
ssh redacted#redacted -t 'zsh -l -c "source ~/.zshrc && ./runTests.sh $1 $2"'
You are invoking three different shells: a local shell, a remote login shell, and a remote zsh shell. You need to carefully specify which one should be responsible for which parameter substitutions.
Your variables live in the local shell, but you are asking the remote login shell to expand them. This is why it fails.
Here's how you can have the local shell substitute them instead:
set -- 7107 development # Assign $1 and $2
ssh redacted#redacted -t "zsh -l -c 'source ~/.zshrc && ./runTests.sh $1 $2'"
Since $1 and $2 are now in double quotes in your local shell, they expand, resulting in zsh -l -c 'source ~/.zshrc && ./runTests.sh 7107 development' on the remote side.
This in turn results in source ~/.zshrc && ./runTests.sh 7107 development in the nested zsh shell.
Ideally you'd also want to escape special characters in your data so that values with quotes or spaces work correctly:
ssh redacted#redacted -t "zsh -l -c 'source ~/.zshrc && ./runTests.sh \$1 \$2' _ $(printf %q "$1") $(printf %q "$2")"
$1, $2, $3, ... are reserved to be used as command parameters, for example if you script name is script.sh, when you run:
./script.sh foo bar baz
$1 will be foo, $2 will be bar and $3 will be baz.
Also you should not use spaces when assign.
Try:
foo=7107
bar=development
ssh redacted#redacted -t 'zsh -l -c "source ~/.zshrc && ./runTests.sh 7107 development"'
ssh redacted#redacted -t 'zsh -l -c "source ~/.zshrc && ./runTests.sh $foo $bar"'
Please note security issues pointed out in comments.

Using /bin/bash -l -c with concatenated commands does not pass environment variables

I'm trying to execute a series of bash commands using /bin/bash -l -c as follows:
/bin/bash -l -c "cmd1 && cmd2 && cmd3..."
What I notice is that if cmd1 happens to export an environment variable, it is not seen by cmd2 and so on. If I run the same concatenated commands without the /bin/bash -l -c option, it just runs fine.
For example, this does not print the value of MYVAR:
$/bin/bash -l -c "export MYVAR="myvar" && echo $MYVAR"
whereas, the following works as expected
$export MYVAR="myvar" && echo $MYVAR
myvar
Can't find why using /bin/bash -l -c won't work here? Or are there any suggestion how to make this work with using /bin/bash -l -c?
variables are exported for child processes, parent process environment can't be changed by child process so consecutive commands (forking sub processes can't see variables exported from preceeding command), some commands are particular becuase don't fork new process but are run inside current shell process they are builtin commands only builtin commands can change current process environment export is a builtin, for more information about builtins man bash /^shell builtin.
Otherwise expansion is done during command parsing:
/bin/bash -l -c "export MYVAR="myvar" && echo $MYVAR"
is one command (note the nested quotes are not doing what you expect because are closing and opening quoted string, myvar is not quoted and may be split). So $MYVAR is expanded to current value before assigned to myvar.
export MYVAR="myvar" && echo $MYVAR
are two commands and $MYVAR because && is bash syntax (not literal like "&&"), is expanded after being assigned.
so that $ have a literal meaning (not expanded) use single quotes or escape with backslash.
/bin/bash -l -c 'export MYVAR="myvar" && echo "$MYVAR"'
or
/bin/bash -l -c "export MYVAR=\"myvar\" && echo \"\$MYVAR\""

Bash script not running in Ubuntu

I'm getting started with bash scripting and made this little script following along a short guide but for some reason when I run the script with sh myscript I get
myscript: 5: myscript: 0: not found running on ubuntu 12.04
here is my script below I should at least see the echo message if no args are set:
#!/bin/bash
#will do something
name=$1
username=$2
if (( $# == 0 ))
then
echo "##############################"
echo "myscript [arg1] [arg2]"
echo "arg1 is your name"
echo "and arg2 is your username"
fi
var1="Your name is ${name} and your username is ${username}"
`echo ${var1} > yourname.txt`
`echo ${var1} > yourname.txt`
Get rid of the backticks.
echo ${var1} > yourname.txt
...for some reason when I run the script with sh myscript...
Don't run it that way. Make the script executable and run it directly
chmod +x myscript
./script
(or run with bash myscript explicitly).
It looks like that expression will work in bash but not in sh. As others pointed out change it to executable, make sure your shebang line is using bash and run it like this:
./myscript
If you want to run it with sh then it is complaining about line 5. Change it to this and it will work in /bin/sh.
if [ $# -ne 0 ]
Check out the man page for test.
Also you don't need the backticks on this line:
echo ${var1} > yourname.txt

Resources