can't read bash script - linux

I ran into this syntax
export ts=${2:-`date "+%s"`}
I know about export and ${2}. I even understand +%s
what does it mean to add :- behind it?
googling these symbols is useless. where do you look up things like this?

The dash causes the expansion to be the value of the variable if it is defined, or the expansion of what follows if the variable is not defined.
Example:
AA=aa
echo ${AA:-11}
echo ${BB:-22}
Will produce the output:
aa
22
Because AA is defined and BB is not.

It means "If the second command line argument has not been passed to the program, use the following value":
`date "+%s"`
It is called "parameter substitution" and is documented here.

Related

Getting "ambiguous redirect" error in my shell script [duplicate]

The following line in my Bash script
echo $AAAA" "$DDDD" "$MOL_TAG >> ${OUPUT_RESULTS}
gives me this error:
line 46: ${OUPUT_RESULTS}: ambiguous redirect
Why?
Bash can be pretty obtuse sometimes.
The following commands all return different error messages for basically the same error:
$ echo hello >
bash: syntax error near unexpected token `newline`
$ echo hello > ${NONEXISTENT}
bash: ${NONEXISTENT}: ambiguous redirect
$ echo hello > "${NONEXISTENT}"
bash: : No such file or directory
Adding quotes around the variable seems to be a good way to deal with the "ambiguous redirect" message: You tend to get a better message when you've made a typing mistake -- and when the error is due to spaces in the filename, using quotes is the fix.
Do you have a variable named OUPUT_RESULTS or is it the more likely OUTPUT_RESULTS?
michael#isolde:~/junk$ ABC=junk.txt
michael#isolde:~/junk$ echo "Booger" > $ABC
michael#isolde:~/junk$ echo "Booger" >> $ABB
bash: $ABB: ambiguous redirect
michael#isolde:~/junk$
put quotes around your variable. If it happens to have spaces, it will give you "ambiguous redirect" as well. also check your spelling
echo $AAAA" "$DDDD" "$MOL_TAG >> "${OUPUT_RESULTS}"
eg of ambiguous redirect
$ var="file with spaces"
$ echo $AAAA" "$DDDD" "$MOL_TAG >> ${var}
bash: ${var}: ambiguous redirect
$ echo $AAAA" "$DDDD" "$MOL_TAG >> "${var}"
$ cat file\ with\ spaces
aaaa dddd mol_tag
I've recently found that blanks in the name of the redirect file will cause the "ambiguous redirect" message.
For example if you redirect to application$(date +%Y%m%d%k%M%S).log and you specify the wrong formatting characters, the redirect will fail before 10 AM for example. If however, you used application$(date +%Y%m%d%H%M%S).log it would succeed. This is because the %k format yields ' 9' for 9AM where %H yields '09' for 9AM.
echo $(date +%Y%m%d%k%M%S) gives 20140626 95138
echo $(date +%Y%m%d%H%M%S) gives 20140626095138
The erroneous date might give something like:
echo "a" > myapp20140626 95138.log
where the following is what would be desired:
echo "a" > myapp20140626095138.log
Does the path specified in ${OUPUT_RESULTS} contain any whitespace characters? If so, you may want to consider using ... >> "${OUPUT_RESULTS}" (using quotes).
(You may also want to consider renaming your variable to ${OUTPUT_RESULTS})
If your script's redirect contains a variable, and the script body defines that variable in a section enclosed by parenthesis, you will get the "ambiguous redirect" error. Here's a reproducible example:
vim a.sh to create the script
edit script to contain (logit="/home/ubuntu/test.log" && echo "a") >> ${logit}
chmod +x a.sh to make it executable
a.sh
If you do this, you will get "/home/ubuntu/a.sh: line 1: $logit: ambiguous redirect". This is because
"Placing a list of commands between parentheses causes a subshell to
be created, and each of the commands in list to be executed in that
subshell, without removing non-exported variables. Since the list is
executed in a subshell, variable assignments do not remain in effect
after the subshell completes."
From Using parenthesis to group and expand expressions
To correct this, you can modify the script in step 2 to define the variable outside the parenthesis: logit="/home/ubuntu/test.log" && (echo "a") >> $logit
I got this error when trying to use brace expansion to write output to multiple files.
for example: echo "text" > {f1,f2}.txt results in -bash: {f1,f2}.txt: ambiguous redirect
In this case, use tee to output to multiple files:
echo "text" | tee {f1,f2,...,fn}.txt 1>/dev/null
the 1>/dev/null will prevent the text from being written to stdout
If you want to append to the file(s) use tee -a
If you are here trying to debug this "ambiguous redirect" error with GitHub Actions. I highly suggest trying it this way:
echo "MY_VAR=foobar" >> $GITHUB_ENV
The behavior I experienced with $GITHUB_ENV is that, it adds it to the pipeline environment variables as my example shows MY_VAR
I just had this error in a bash script. The issue was an accidental \ at the end of the previous line that was giving an error.
One other thing that can cause "ambiguous redirect" is \t \n \r in the variable name you are writing too
Maybe not \n\r? But err on the side of caution
Try this
echo "a" > ${output_name//[$'\t\n\r']}
I got hit with this one while parsing HTML, Tabs \t at the beginning of the line.
This might be the case too.
you have not specified the file in a variable and redirecting output to it, then bash will throw this error.
files=`ls`
out_file = /path/to/output_file.t
for i in `echo "$files"`;
do
content=`cat $i`
echo "${content} ${i}" >> ${out_file}
done
out_file variable is not set up correctly so keep an eye on this too.
BTW this code is printing all the content and its filename on the console.
if you are using a variable name in the shell command, you must concatenate it with + sign.
for example :
if you have two files, and you are not going to hard code the file name, instead you want to use the variable name
"input.txt" = x
"output.txt" = y
then ('shell command within quotes' + x > + y)
it will work this way especially if you are using this inside a python program with os.system command probably
In my case, this was a helpful warning, because the target variable (not the file) was misspelled and did not exist.
echo "ja" >> $doesNotExist
resulting in
./howdy.sh: line 4: $doesNotExist: ambiguous redirect
For my case, if I specify the output file via a env (e.g $ENV_OF_LOG_FILE), then will get the error ambiguous redirect.
But, if I use plain text as file path (e.g /path/to/log_file), then there is no error.

Indirect expansion returns variable name instead of value

I am trying to set up some variables using indirect expansion. According to the documentation I've read, the set up should be simple:
var1=qa
qa_num=12345
varname="${var1}_ci"
echo ${!varname}
I should be getting "12345". Instead, the output is "varname". If I remove the exclamation point, I end up with "qa_ci", not "12345"
This should be a relatively simple solution, so I'm not sure what I'm missing, if anything.
Your code defines qa_num, but the varname assignment references qa_ci. As a result, your echo was expanding nonexistent qa_ci, giving empty results. Changing the varname assignment fixes the problem on my system.
Example: foo.sh:
#!/bin/bash
var1=qa
qa_num=12345
varname="${var1}_num" # <=== not _ci
echo "${!varname}" # I also added "" here as a general good practice
Output:
$ bash foo.sh
12345

bash variable in string substitution

I am trying to do string substitution in bash, want to understand it better.
I crafted a success case like this:
a=abc_de_f
var=$a
echo ${var//_/-}
outout is abc-de-f. This works.
However, the following script fails:
a=abc_de_f
echo ${$a//_/-}
The error message is ${$a//_/-}: bad substitution.
It seems like related to how we can use a variable in substitution. Why this fails? How bash handles variables in this case?
Also, what is the best practice to handle escape characters in bash string substitution?
In the second case, you don't need the second $ as a is the string.
a=abc_de_f
echo ${a//_/-}
If you wanted to add a level of indirection, you can use ! before the variable as in
a=abc_de_f
b=a
echo ${b//_/-}
will output a, while
echo ${!b//_/-}
will output abc-de-f.
See here for a discussion on the art of escaping in BASH

Bash variable assignment not working expected

status=0
$status=1
echo $status
Can anyone tell my what i am doing wrong with this?
It gives me the following error:
0=1: command not found
This line is OK - it assigns the value 0 to the variable status:
status=0
This is wrong:
$status=1
By putting a $ in front of the variable name you are dereferencing it, i.e. getting its value, which in this case is 0. In other words, bash is expanding what you wrote to:
0=1
Which makes no sense, hence the error.
If your intent is to reassign a new value 1 to the status variable, then just do it the same as the original assignment:
status=1
Bash assignments can't have a dollar in front. Variable replacements in bash are like macro expansions in C; they occur before any parsing. For example, this horrible thing works:
foof="[ -f"
if $foof .bashrc ] ; then echo "hey"; fi
Only use the $ when actually using the variable in bash. Omit it when assigning or re-assining.
e.g.
status=0
status2=1
status="$status2"
also this ugly thing works too :
status='a'
eval $status=1
echo $a
1

Bash Shell - The : Command

The colon command is a null command.
The : construct is also useful in the conditional setting of variables. For example,
: ${var:=value}
Without the :, the shell would try to evaluate $var as a command. <=???
I don't quite understand the last sentence in above statement. Can anyone give me some details?
Thank you
Try
var=badcommand
$var
you will get
bash: badcommand: command not found
Try
var=
${var:=badcommand}
and you will get the same.
The shell (e.g. bash) always tries to run the first word on each command line as a command, even after doing variable expansion.
The only exception to this is
var=value
which the shell treats specially.
The trick in the example you provide is that ${var:=value} works anywhere on a command line, e.g.
# set newvar to somevalue if it isn't already set
echo ${newvar:=somevalue}
# show that newvar has been set by the above command
echo $newvar
But we don't really even want to echo the value, so we want something better than
echo ${newvar:=somevalue}.
The : command lets us do the assignment without any other action.
I suppose what the man page writers meant was
: ${var:=value}
Can be used as a short cut instead of say
if [ -z "$var" ]; then
var=value
fi
${var} on its own executes the command stored in $var. Adding substitution parameters does not change this, so you use : to neutralize this.
Try this:
$ help :
:: :
Null command.
No effect; the command does nothing.
Exit Status:
Always succeeds.

Resources