I'm trying to pass commands as an argument to my script
> ./index.bat "echo foo && echo bar"
script:
#echo off
echo %1%
set f=%1%
echo %f%
set f=%f:~1,-1%
echo %f%
output:
"echo foo && echo bar"
"echo foo && echo bar"
bar
echo foo
why is the second part of the command in the argument executed?
Related
I'm working on a bash script to grep a file then to run a perl command. I know the commands work since I have been using them, but I can't seem to get them to work for the bash script. I would appreciate any help.
When I output $1 and so on it has the values, but when I output the grep command with them in it. I get file can't be found or blank spaces.
#! /bin/bash
usage()
{
echo "Usage: $0"
echo $'\a'Supply 4 arguments
echo $0 arg1 arg2 arg3 arg4
echo "1. search parameters for bookmarks"
echo "2. What file to grep"
echo "3. file to temporaly store results"
echo "4. what file to store the final version"
exit 1
}
main()
{
# if [ "$#" -lt "4" ]
# then
# usage
# else
echo "beginning grep"
grep -ir "$1" "$2" >> "$3"
echo "grep complete"
# echo "beginning perl command"
# perl -0ne 'print "$2\n$1\n" while (/a href=\"(.*?)\">(.*?)<\/a>/igs)' "$3" >> "$4"
# echo "perl command complete"
# echo "done"
# exit 1
# fi
}
main
echo $0
echo $1
echo $2
echo $3
echo $4
Remember that when a bash function is called, the positional parameters are temporarily replaced with the function's parameters. So either don't make your mainline a function or pass your main function the input parameters. To pass the script's parameters to your main function, do this:
main "$#"
In bash/zsh, the following check for checking a variable doesn't work:
#!/bin/zsh
set -o nounset # Error when unset vars are used
set -o errexit
if [ -n ${foo-x} ]; then
echo "Foo exists!"
else
echo "Foo doesn't exist"
fi
Because foo is expanded even if it doesn't exist, nounset triggers, and it exits. How can I check the existence of a variable without expanding it? I really like nounset and errexit, so I'd rather not disable them halfway each time I want to check if some var is set.
You can make a function for the check (and turn of the nounset only in the function), call the function with the variable name and use the indirect variable referencing. something like the next:
set -o nounset
set -o errexit
isset() {
set +o nounset
[[ -n "${!1+x}" ]]
result=$?
set -o nounset
return $result
}
a=1
#call the "isset" with the "name" not value, so "a" and not "$a"
isset a && echo "a is set" || echo "a isnt set"
b=''
isset b && echo "b is set" || echo "b isnt set"
isset c && echo "c is set" || echo "c isnt set"
prints:
a is set
b is set
c isnt set
EDIT
Just learned a clean method, use the -v varname (need bash 4.2+ or zsh 5.3+)
[[ -v a ]] && echo "a ok" || echo "a no"
[[ -v b ]] && echo "b ok" || echo "b no"
[[ -v c ]] && echo "c ok" || echo "c no"
I want to check if a command line option exists when running a shell script, example
./test.sh arg1 arg2 arg3 arg4
Want to check if one of the argument is say arg3 (not necessarily the third argument)
The quick solution is to use a for loop and check if one of the argument matches a given string, but is there a better way to do it something of the form 'arg3' in $#.
(assuming bash)
I would do this:
have_arg3=false
for arg; do
if [[ $arg == "arg3" ]]; then
have_arg3=true
break
fi
done
if $have_arg3; then
echo "arg3 is present
fi
but you could do this (all quotes and spaces below are required!):
if [[ " $* " == *" arg3 "* ]]; then
echo "arg3 is present"
fi
can be encapsulated in a function:
$ arg_in_args () (
arg=$1
shift
IFS=:
[[ "$IFS$*$IFS" == *"$IFS$arg$IFS"* ]]
)
$ set -- foo bar baz
$ if arg_in_args "arg3" "$#"; then echo Y; else echo N; fi
N
$ if arg_in_args "baz" "$#"; then echo Y; else echo N; fi
Y
I want to implement a bash function that runs its arguments as a command, while (maybe optionally) printing the command before. Think of an installation script or test runner script.
Just using
function run () {
echo "Running $#"
"$#"
}
would not allow me to distinguish a call from run foo arg1 arg2 and run foo "arg1 arg2", so I need to properly escape arguments.
My best shot so far is
function run () {
echo -n "Running"
printf " %q" "$#"
echo
"$#"
}
Which works:
$ run echo "one_argument" "second argument" argument\"with\'quotes
Running echo one_argument second\ argument argument\"with\'quotes
one_argument second argument argument"with'quotes
but is not very elegant. How can I achieve an output of
$ run echo "one_argument" "second argument" argument\"with\'quotes
Running echo one_argument "second argument" "argument\"with'quotes"
one_argument second argument argument"with'quotes
i.e. how can I make printf to put quotation marks around arguments that need quoting, and properly escape quotes therein, so that the output can be copy’n’pasted correctly?
This will quote everything:
run() {
printf "Running:"
for arg; do
printf ' "%s"' "${arg//\"/\\\"}"
done
echo
"$#"
}
run echo "one_argument" "second argument" argument\"with\'quotes
Running: "echo" "one_argument" "second argument" "argument\"with'quotes"
one_argument second argument argument"with'quotes
This version only quotes arguments containing double quotes or whitespace:
run() {
local fmt arg
printf "Running:"
for arg; do
[[ $arg == *[\"[:space:]]* ]] && fmt=' "%s"' || fmt=" %s"
printf "$fmt" "${arg//\"/\\\"}"
done
echo
"$#"
}
run echo "one_argument" "second argument" argument\"with\'quotes
Running: echo one_argument "second argument" "argument\"with'quotes"
one_argument second argument argument"with'quotes
I don't think there's an elegant solution to what you want, because "$#" is handled by bash before any command ever gets to see it. You'll have to manually re-construct the command-line:
#!/bin/bash
function run() {
echo -n "Running:"
for arg in "$#"; do
arg="$(sed 's/"/\\&/g' <<<$arg)"
[[ $arg =~ [[:space:]\\\'] ]] && arg=\"arg\"
echo -n " $arg"
done
echo ""
"$#"
}
run "$#"
Output:
$ ./test.sh echo arg1 "arg 2" "arg3\"with'other\'\nstuff"
Running: echo arg1 "arg 2" "arg3\"with'other\'\nstuff"
arg1 arg 2 arg3"with'other\'\nstuff
Note that there are some corner cases where you won't get the exact input command line. This happens when you pass arguments that bash expands before passing them on, e.g.:
$ ./test.sh echo foo'bar'baz
Running: echo foobarbaz
foobarbaz
$ ./test.sh echo "foo\\bar"
Running: echo "foo\bar"
foobar
Is it possible with bash to execute a command from shell and if it returns a certain value (or an empty one) execute a command?
if [ "echo test" == "test"]; then
echo "echo test outputs test on shell"
fi
Yes, you can use backticks or $() syntax:
if [ $(echo test) = "test" ] ; then
echo "Got it"
fi
You should replace $(echo test) with
"`echo test`"
or
"$(echo test)"
if the output of the command you run can be empty.
And the POSIX "stings are equal" test operator is =.
something like this?
#!/bin/bash
EXPECTED="hello world"
OUTPUT=$(echo "hello world!!!!")
OK="$?" # return value of prev command (echo 'hellow world!!!!')
if [ "$OK" -eq 0 ];then
if [ "$OUTPUT" = "$EXPECTED" ];then
echo "success!"
else
echo "output was: $OUTPUT, not $EXPECTED"
fi
else
echo "return value $OK (not ok)"
fi
You can check the exit_code of the previous program like:
someprogram
id [[ $? -eq 0 ]] ; then
someotherprogram
fi
Note, normally the 0 exit code means successful finish.
You can do it shorter:
someprogram && someotherprogram
With the above someotherprogram only executes if someprogram finished successfully. Or if you want to test for unsuccessful exit:
someprogram || someotherprogram
HTH
Putting the command betweeen $( and ) or backticks (`) will substitute that expression into the return value of the command. So basically:
if [ `echo test` == "test"]; then
echo "echo test outputs test on shell"
fi
or
if [ $(echo test) == "test"]; then
echo "echo test outputs test on shell"
fi
will do the trick.