I'm trying to run a simple shell script example:
STR="qwe;ert;rty;tii"
IFS=';' read -r NAMES <<< "$STR"
This is giving me the following error message:
syntax error: got <&, expecting Word
I'm not exactly sure why this isn't working. I thought the syntax I used was
correct and I tried comparing to other examples and I saw the syntax was almost
identical.
Any feedback would help
Thanks
This is MKS bash, not GNU bash. It's not really bash, and doesn't support the genuine shell's syntax.
There are perfectly good (...well, reasonably adequate) builds of GNU bash for Windows. Use them.
Particularly, in real bash, to split a semicolon-separated string into an array of names:
str='qwe;ert;rty;tii'
IFS=';' read -r -a names <<<"$str"
...which you can then verify with
declare -p names
or emit one-to-a-line with
printf '%s\n' "${names[#]}"
Related
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'm getting this error in a HP-UX machine
+ IFS=;
/home/machine1/folder/borrado_de_logs.sh[45]: read: A specified flag is not valid for this command.
And I'm using this code
head -1 $rutatemporal/logfechas.log > $rutatemporal/cabecera.txt
cabecera=`cat $rutatemporal/cabecera.txt`
IFS=';' read -a arreglo<<EOF
$cabecera
EOF
In Hp-UX its seems that read -a is not allowed
what argument I should use with read?
the content of cabecera.txt is this:
2019-02-01;/home/user/deletelogs/somelog.log
It's probably because -a is not a POSIX compliant flag support for the read command. So it is not surprising that the default shell available in your HP-UX machine is not supporting it.
You can still use the read command without -a to split and store on individual variable names as below. Also you don't need a here-doc to read from the input file, but rather use the read command directly on the file itself
IFS=\; read -r date path < "$rutatemporal"/cabecera.txt
echo "$date"
echo "$path"
Type
$ help read
and you can see the available options and their meaning.
I'm trying to write a program that takes a file's name, and puts the date on it. So I'm trying to get substrings for the filename itself, and the extension.
I'm new to BASH so maybe I'm missing something here, but following online guides, it seems like this should work-
#!/bin/bash
echo "Type filename in this dir"
read filename
file=`filename%.*`
end=`filename##*.`
today=`date +%d-%m-%y`
dated="${file}_${today}.${end}"
cat $filename > $dated
But the computer returns these errors-
./fileDater.sh: line 5: filename%.*: command not found
./fileDater.sh: line 6: filename##*.: command not found
I'm using an Ubuntu Subsystem on Windows 10, if that's important.
It seems you've got some confusion about bash substitution; You're trying to execute a command sub-shell instead (eg. `variable##*.`) — it should be using ${ ... } .
#!/bin/bash
echo "Type filename in this dir"
read -r filename
file=${filename%.*}
end=${filename##*.}
today=$(date +%d-%m-%y)
dated="${file}_${today}.${end}"
cat "$filename" > "$dated"
I haven't tried your script, although I believe that is your main issue.
EDIT: Regarding the use of backticks (`...`)
In the form of `COMMAND` it's more or less obsolete for Bash, since it has some trouble with nesting ("inner" backticks need to be escaped) and escaping characters.
Use $(COMMAND) instead — it's also POSIX!
↳ Bash Hackers Wiki - Command Substitution
I need to declare variables in a bash shell script for which both names and values are taken from another command's output.
For the sake of this question, I will use a temporary file tmp:
$ cat tmp
var1="hello world"
var2="1"
... and use it for my mock command below.
In the end, I need to have the variables $var1 and $var2 set with respectively hello world and 1, with the variable names var1 and var2 taken directly from the input.
Here is what I got so far:
$ cat tmp|while read line; do declare $line; done
I know I don't need to use catbut this is to simulate the fact that the input is taken from the output of an other command and not in a file.
This doesn't work. I get:
bash: declare: `world"': not a valid identifier
and
$ echo $var1; echo $var2
$
I don't understand why this doesn't work since I can do this:
declare var1="hello world"
... with expected result. I assumed this would be equivalent, but I'm clearly wrong.
I found this answer as the closest thing to my problem, but not quite since it relies on a file to source. I would like to avoid that. I found other answers that uses eval but I'd prefer to avoid that as well.
Maybe there are subtleties in the use of quotes I don't understand.
If the only way is to use a temporary file and source it that is what I'll do, but I think there must be another way.
A good suggestion when writing a shell script is that always double quoting the variable. Otherwise, it will be affected by the shell word splitting.
while read line; do
declare "$line"
done < <(echo "var1=hello world")
And why echo "var1=hello world" | while read line; do export "$line"; done won't work? Because pipe is a sub-shell, it creates var1 in the sub-shell, it won't impact the current shell. So it can't be set in the current shell.
As an alternative, use process substitution, you can obtain the output as a temporary file. So it will create the variable in the current shell.
I have a bash script with the following line. The variables start_time and start_files[$i] are floating point numbers. I want to compare them using the command bc as follows:
result1=$(bc -l <<< $start_time'>='${start_files[$i]})
When I run the script I always receive the following error.
(standard_in) 1: syntax error
I've checked that this error is due to this line. What am I doing wrong? The thing that this happens to me when using bash 4.1, with bash 4.3 runs fine. However I need to run the script with bash 4.1.
The bc command works however the input doesn't work. The variable start_files is read from a file with this command
IFS=, read -r -a start_files <<< $(head -n 1 file.txt)
Basically I want to read all the values from the first line separated by a coma and store them to different positions of the array. However using bash 4.1 all the values end up stored in start_files[0]. How can I solve this? This lines works for bash 4.3
I would suggest that you use double quotes:
result1=$(bc -l <<<"$start_time >= ${start_files[$i]}")
This way, you are echoing a single string to bc, containing your variables.
Are you reading the values from a file with DOS-style line endings perhaps?
$ start_time=$'1.5\r'
$ i=1
$ start_files[$i]=$'2.5\r'
$ bc -l <<< "$start_time >= ${start_files[$i]}"
(standard_in) 1: illegal character: ^M
(standard_in) 1: illegal character: ^M
You may avoid the here-string, add double quotes and remove a $:
result1=$(echo "$start_time >= ${start_files[i]}" | bc -l)
It would help to give the version of bc you're using. I'd guess it's not the same on the two systems. By the way, your error has nothing to do with Bash.
POSIX bc clearly states that a comparison (referred to as relational_expression in POSIX' bc Specification can only appear in a while, for or if construct.
So, first thing you'll try is this:
bc <<< "if($start_time >= ${start_files[$i]}) 1 else 0"
This might not work, as POSIX' bc doesn't allow an else clause in an if statement. (As amazing as it may seem, you read that last sentence correctly).
If your bc is really POSIX stuck up, then you'll have to do some ugly stuff as, e.g.,
bc <<< "ret=0; if($start_time >= ${start_files[$i]}) { ret=1 } ret"
or even something worse (sorry, I don't have a POSIX bc here, so I can't experiment—if someone has one at hand or remembers the syntax off the top of his head, please edit this line with the proper syntax).
Good luck!