I'm running OSX 10.6, and I have this very simple script in a file "hi.sh":
#!/bin/bash
echo "hi"
I've already run "chmod +x hi.sh". Now, I've tried both of the following:
$ ./hi.sh
$ bash hi.sh
and neither outputs "hi". What could be the problem?
It could be that you used an editor that defaults to \r as line separator, which was the separator used under classic (pre OS X) MacOS. Try wc -l hi.sh; if you get 0 lines, then it's a line ending problem. Your script would then be just a single comment line, which would of course do nothing.
Related
I have a simple Bash script:
#!/usr/bin/env bash
read X
echo "X=$X"
When I execute it with ./myscript.sh it works. But when I execute it with cat myscript.sh | bash it actually puts echo "X=$X" into $X.
So this script prints Hello World executed with cat myscript.sh | bash:
#!/usr/bin/env bash
read X
hello world
echo "$X"
What's the benefit of executing a script with cat myscript.sh | bash? Why doesn't do it the same things as if I execute it with ./myscript.sh?
How can I avoid Bash to execute line by line but execute all lines after the STDIN reached the end?
Instead of just running
read X
...instead replace it with...
read X </dev/tty || {
X="some default because we can't read from the TTY here"
}
...if you want to read from the console. Of course, this only works if you have a /dev/tty, but if you wanted to do something robust, you wouldn't be piping from curl into a shell. :)
Another alternative, of course, is to pass in your value of X on the command line.
curl https://some.place/with-untrusted-code-only-idiots-will-run-without-reading \
| bash -s "value of X here"
...and refer to "$1" in your script when you want X.
(By the way, I sure hope you're at least using SSL for this, rather than advising people to run code they download over plain HTTP with no out-of-band validation step. Lots of people do it, sure, but that's making sites they download from -- like rvm.io -- big targets. Big, easy-to-man-in-the-middle-or-DNS-hijack targets).
When you cat a script to bash the code to execute is coming from standard input.
Where does read read from? That's right also standard input. This is why you can cat input to programs that take standard input (like sed, awk, etc.).
So you are not running "a script" per-se when you do this. You are running a series of input lines.
Where would you like read to read data from in this setup?
You can manually do that (if you can define such a place). Alternatively you can stop running your script like this.
I am banging my head against the wall about the Bad substitution error in Bash. Consider the following code:
getApiName() {
IFS='-' # hyphen (-) is set as delimiter
read -ra array <<< "$1" # str is read into an array as tokens separated by IFS
for i in "${array[#]}"; do # access each element of array
output+=${i^} #set first letter to uppercase
done
IFS=' '
echo ${output}
}
When I do the following:
getApiName "vl-date-picker"
I get line 21: ${i^}: bad substitution
I have no clue on what's wrong.
Can you guys help me please?
Thanks in advance.
Regards
General Answer
I cannot reproduce your problem. I see two possible reasons:
You are using a non-bash shell.
Check this by adding the command ps to the script and look at the output. If there is no bash in the output, then you are running something different. A shebang #! /bin/bash at the beginning of your script helps to ensure that bash is used but is not a guarantee. ✱
You have an old version of bash which does not support ${i^}
(for instance that 15 (!) year old version pre-installed on Mac OS X).
You can check your bash version using bash --version. ${i^} was introduced in bash 4.0, as can be read here (search for hh. There are new case-modifying word expansions) or here.
Either way, you can use a different command which should work in all Posix shells.
If you have the GNU version of sed (check with sed --version) this command could be
getApiName() {
printf %s "$1" | sed -E 's/(^|-+)(.)/\U\2/g'
}
Nmp-Specific Answer
✱
The documentation of npm-run-script states
The actual shell your script is run within is platform dependent. By default, on Unix-like systems it is the /bin/sh command, on Windows it is the cmd.exe. The actual shell referred to by /bin/sh also depends on the system. As of npm#5.1.0 you can customize the shell with the script-shell configuration.
So to fix your problem you simply have to configure npm such that bash is used instead.
As a workaround, you could also call bash directly in your script. The simplest way to do so is a here-document:
bash -s -- "$#" <<"EOF"
# your original script here
EOF
I'd like to execute a range of lines from a shell script from a running shell and using the current shell's environment.
For example, in a script that sets a variable to something I don't want to type (say an API key or MAC address):
line
1 #!/bin/zsh
2
3 # Set the MAC address:
4 MAC="12-34-56-78-90-ab-cd"
...
...and in my shell, I'd like to grab line 4 above, run it, and have $MAC exist in that environment
I've tried sed -n '4p' script.zsh | zsh but that doesn't affect the current shell I'm working in:
$ MAC="this is not a MAC address"
$ sed -n '4p' script.zsh | zsh
$ echo $MAC
---
this is not a MAC address
I could just copy and paste, but I'd like a solution I can use without touching my mouse - or when I don't have a mouse available.
You could combine your sed command with a process substitution and source it:
source <(sed -n '4p' script.zsh)
though you might want to use a pattern match for the print line in case the line numbers shift.
source <(sed -n '/^MAC=/p' script.zsh)
I am pulling my hair out try to get a script to work on cygwin. Here's the latest version of the script I am trying to run:
$ cat start_vm_2.sh
#!/bin/sh
VMRUN='/cygdrive/c/\"Program Files (x86)\"/VMware/VMware\ VIX/vmrun"'
echo "VMRUN is [$VMRUN]"
ARGS='-T ws start \"C:\\Users\\red\\Documents\\Virtual Machines\\myvm-dev-006 \(2\)\\myvm-dev-006 \(2\).vmx\"'
echo "ARGS is [$ARGS]"
And this is the error message I get:
$ ./start_vm_2.sh
VMRUN is [/cygdrive/c/\"Program Files (x86)\"/VMware/VMware\ VIX/vmrun"]
ARGS is [-T ws start \"C:\\Users\\red\\Documents\\Virtual Machines\\myvm-dev-006 \(2\)\\myvm-dev-006 \(2\).vmx\"]
./start_vm_2.sh: line 8: /cygdrive/c/\"Program: No such file or directory
You should run it as bash instead and store your arguments as arrays. Also, do not add literal quotes to your spaces:
#!/bin/bash
VMRUN="/cygdrive/c/Program Files (x86)/VMware/VMware VIX/vmrun"
echo "VMRUN is [$VMRUN]"
ARGS=(-T ws start 'C:\Users\red\Documents\Virtual Machines\myvm-dev-006 (2)\myvm-dev-006 (2).vmx')
echo "ARGS is [${ARGS[*]}]"
"$VMRUN" "${ARGS[#]}"
Run bash script.sh.
this might be your problem... I was having the same issue until I figured out my script had Windows special characters (cat -e script.ksh)... so I did a dos2unix to the file and it started to flow as I wanted
Hope this is useful
I'm trying to run the CodeSourcery arm-2011.03.42 BASH script in Ubuntu 12.04. At the top of the script is the following:
#! /usr/bin/env bash
But, when I execute it, I get the following errors:
line 140: grep: command not found
line 140: sed: command not found
I can run both grep and sed from the command line, but not in the script.
Here's what line 140 look like
env_var_list=$(export | \
grep '^declare -x ' | \
sed -e 's/^declare -x //' -e 's/=.*//')
If I change the first line to
#!/bin/sh
I get the following error:
Line 51: Syntax error: "(" unexpected (expecting "}")
Here's what Line 51 looks like
check_pipe() {
local -a status=("${PIPESTATUS[#]}") #<-- Line 51
local limit=$1
local ix
The #<-- Line 51 actually doesn't appear in the shell script. I just added it to this post for clarity.
I've tried dos2unix and a number of other things, but I just can't win. I would very much appreciate your help.
I changed this line in the script
pushenvvar PATH /usr/local/tools/gcc-4.3.3/bin
to
pushenvvar PATH /usr/local/tools/gcc-4.3.3/bin:/bin
and it seems to work now.
Shell script must be bash as arrays don't exist in sh.
Check your PATH evironment variable, and the path of grep and sed /bin normally.
Ther might be several possiable reasons.
As #AntonioD pointed out, there must not be any space between '#!' and '/usr/bin/env' at the begining of the file.
The grep and sed command does not exists in your $PATH, checkout your /bin and /user/bin to see if they are existed, or run which grep and which sed in your shell.
If grep and sed are indeed existed, you need to make sure they have right access.They should be accessable and executable, in general, this should not happen.
You must not using #!/bin/sh instead of #!/usr/bin/evn or #!/bin/bash, because that would cause the shell run in POSIX compatible mode in which most of bash advanced features such as arrays are not functional.
If all of above are not the case, then it is really weird.