I have to find a way to have my script read from one of these three options:
a file argument
standard input
a previously established environment variable
Here's what I currently have:
#!/bin/bash
key=$1
[ $# -ge 1 -a -f "$2" ] && input="$2" || [ -f "$INPUT" ] && input="$INPUT" || input="-"
echo $input
Only the environment variable refuses to work, the rest works fine.
I've tried using the export INPUT="pathnametofile" before but it doesn't make any difference, I end up with the shell asking me to enter info as if I called on cat.
The problem in your script
Your attemp is not working due to the way the shell processes a Lists of Commands:
‘&&’ and ‘||’ have equal precedence.
AND and OR lists are executed with left associativity.
Your sentence:
[ $# -ge 1 -a -f "$2" ] && input="$2" || [ -f "$INPUT" ] && input="$INPUT" || input="-"
does the same as follows:
[ $# -ge 1 -a -f "$2" ] && input="$2"
[ $? -eq 0 ] || [ -f "$INPUT" ]
[ $? -eq 0 ] && input="$INPUT"
[ $? -eq 0 ] || input="-"
Now yo may see why your unexpected behaviour.
A better attempt grouping commands
{ [ $# -ge 1 -a -f "$2" ] && input="$2"; } || { [ -f "$INPUT" ] && input="$INPUT"; } || input="-"
Now, due to precedence, the first group is not needed at all:
[ $# -ge 1 -a -f "$2" ] && input="$2" || { [ -f "$INPUT" ] && input="$INPUT"; } || input="-"
Furthermore, unless you have set the positional parameters by hand, you can remove the first check (after all, if $2 is emtpy, -f "" fails the same).
[ -f "$2" ] && input="$2" || { [ -f "$INPUT" ] && input="$INPUT"; } || input="-"
An alternative with the if conditional construct
if [ -f "$2" ]; then
input=$2
elif [ -f "$INPUT" ]; then
input=$INPUT
fi
echo "${input:=-}"
untested, but you'll probably have better luck with if commands, and test that the variable is not empty:
if [ $# -ge 1 -a -f "$2" ]; then
input="$2"
elif [ -n "$INPUT" -a -f "$INPUT" ]; then
input="$INPUT"
else
input="-"
fi
Related
How is it possible to get an URL parameter like /?photo=1.png into a shell script as a variable, running into a cgi-bin container on apache?
Edit
Iam generating a list of all files in a directory.
#!/bin/bash
echo "Content-type: text/html"
echo
for file in /var/www/html/export/tui/*;
do
echo "<a href='/cgi-bin/test.cgi?file="${file: -27}"'>"${file: -27}"</a><br>";
done;
Now, i want to give the file name as a parameter into a second script, who needs this for reading it.
I found a solution who take the URL parameter and give it into my script
#!/bin/bash
echo "Content-type: text/html"
echo
function cgi_decodevar()
{
[ $# -ne 1 ] && return
local v t h
t="${1//+/ }%%"
while [ ${#t} -gt 0 -a "${t}" != "%" ]; do
v="${v}${t%%\%*}" # digest up to the first %
t="${t#*%}" # remove digested part
if [ ${#t} -gt 0 -a "${t}" != "%" ]; then
h=${t:0:2}
t="${t:2}"
v="${v}"`echo -e \\\\x${h}`
fi
done
echo "${v}"
return
}
function cgi_getvars()
{
[ $# -lt 2 ] && return
local q p k v s
case $1 in
GET)
[ ! -z "${QUERY_STRING}" ] && q="${QUERY_STRING}&"
;;
POST)
cgi_get_POST_vars
[ ! -z "${QUERY_STRING_POST}" ] && q="${QUERY_STRING_POST}&"
;;
BOTH)
[ ! -z "${QUERY_STRING}" ] && q="${QUERY_STRING}&"
cgi_get_POST_vars
[ ! -z "${QUERY_STRING_POST}" ] && q="${q}${QUERY_STRING_POST}&"
;;
esac
shift
s=" $* "
while [ ! -z "$q" ]; do
p="${q%%&*}"
k="${p%%=*}"
v="${p#*=}"
q="${q#$p&*}"
[ "$1" = "ALL" -o "${s/ $k /}" != "$s" ] && \
export "$k"="`cgi_decodevar \"$v\"`"
done
return
}
cgi_getvars BOTH ALL
echo $foo
I know how to check for a file in bash using this code
file=$1
if [ -f "$file" ]
then
...
fi
But I want to do something when it's not a file.
file=$3
if [ "$1" == "" ] || [ "$2" == "" ] || [ $file is not a file??? ]
then
echo "use: notEmpty notEmpty file"
fi
Can anyone help me out?
if [ "$1" == "" ] || [ "$2" == "" ] || [ ! -f "$file" ]
The whitespaces after [ and before ] are important.
I'm having some trouble terminating a shell. I'm starting several filkontroll.sh in the background to regularly check files to see if they have been changed or deleted. It seems to be running fine except that when all the files have been modified, the program won't terminate. It's seems to be stuck in the for-loop somehow.
filkontroll.sh :
#!/bin/bash
clear
declare -i status=1
if [ -f $1 ]
then
status=0
timestamp=$(stat -f "%Sm" -t "%H%M%S" $1)
fi
while [ 0 ]
do
if [ -f $1 ] && [ $status -eq 1 ]
then
echo "Filen $1 ble opprettet."
break
elif [ ! -f $1 ] && [ $status -eq 0 ]
then
echo "Filen $1 ble slettet."
break
elif [ -f $1 ]
then
sistEndret=$(stat -f "%Sm" -t "%H%M%S" $1)
if [ ! $sistEndret -eq $timestamp ]
then
echo "Filen $1 ble endret."
break
fi
fi
sleep $2
done
kontrollflerefiler.sh:
#!/bin/bash
clear
for fil in $#
do
. filkontroll.sh $fil 2 &
done
Suppose I am writing the following in a bash script:
if [ -z $a ] || [ -z $b ] ; then
usage
fi
It works but I would like to write it with short-circuiting as follows:
[ -z $a ] || [ -z $b ] || usage
Unfortunately it does not work. What am I missing ?
You want to execute usage in case either 1st or 2nd condition are accomplished. For that, you can do:
[ -z $a ] || [ -z $b ] && usage
Test:
$ [ -z "$a" ] || [ -z "$b" ] && echo "yes"
yes
$ b="a"
$ [ -z "$a" ] || [ -z "$b" ] && echo "yes"
yes
$ a="a"
$ [ -z "$a" ] || [ -z "$b" ] && echo "yes"
$
You could make use of the following form:
[[ expression ]]
and say:
[[ -z "$a" || -z "$b" ]] && usage
This would execute usage if either a or b is empty.
Always quote your variables. Saying
[ -z $a ]
if the variable a is set to foo bar would return an error:
bash: [: foo: binary operator expected
How can I consolidate the following if statements into a single line?
if [ $# -eq 4 ]
then
if [ "$4" = "PREV" ]
then
print "yes"
fi
fi
if [ $# -eq 3 ]
then
if [ "$3" = "PREV" ]
then
print "yes"
fi
fi
I am using ksh.
Why does this give an error?
if [ [ $# -eq 4 ] && [ "$4" = "PREV" ] ]
then
print "yes"
fi
Error:
0403-012 A test command parameter is not valid.
Try this:
if [[ $# -eq 4 && "$4" == "PREV" ]]
then
print "yes"
fi
You can also try putting them all together like this:
if [[ $# -eq 4 && "$4" == "PREV" || $# -eq 3 && "$3" == "PREV" ]]
then
print "yes"
fi
Do you just want to check if the last argument is "PREV"? If so, you can also do something like this:
for last; do true; done
if [ "$last" == "PREV" ]
then
print "yes"
fi
'[' is not a grouping token in sh. You can do:
if [ expr ] && [ expr ]; then ...
or
if cmd && cmd; then ...
or
if { cmd && cmd; }; then ...
You can also use parentheses, but the semantics is slightly different as the tests will run in a subshell.
if ( cmd && cmd; ); then ...
Also, note that "if cmd1; then cmd2; fi" is exactly the same as "cmd1 && cmd2", so you could write:
test $# = 4 && test $4 = PREV && echo yes
but if your intention is to check that the last argument is the string PREV, you might consider:
eval test \$$# = PREV && echo yes
Try this :
if [ $# -eq 4 ] && [ "$4" = "PREV" ]
then
print "yes"
fi