Argument evaluation - bash

Look at this bash script (script.sh):
#!/bin/bash
echo "aaa"
echo "bbb"
...
echo $1
...
Now, i am trying to run this script this way:
./script.sh $(cat file1)
I have a problem:
the "cat file1" is run before script.sh. Bash is evaluating all arguments before running script.sh
I would like to run "cat file1" inside script.sh, on the "echo $1" line.
How can i do this ?
I have tried this:
./script.sh $(eval 'cat file1')
But it gives me the same result...
Thanks

I think, there is no way unless you can modify the script script.sh.
If you can modify script.sh, you can write your script like this:
#!/bin/bash
echo "$($1)"
Then call it in this way:
./script.sh "cat file1"
This means, you pass the command to be executed to the script and you echo the result of the executed command in the script.
But the above script is a little cumbersome. This one is simpler and would do the same:
#!/bin/bash
$1

Related

Redirect copy of stdin to file from within bash script itself

In reference to https://stackoverflow.com/a/11886837/1996022 (also shamelessly stole the title) where the question is how to capture the script's output I would like to know how I can additionally capture the scripts input. Mainly so scripts that also have user input produce complete logs.
I tried things like
exec 3< <(tee -ia foo.log <&3)
exec <&3 <(tee -ia foo.log <&3)
But nothing seems to work. I'm probably just missing something.
Maybe it'd be easier to use the script command? You could either have your users run the script with script directly, or do something kind of funky like this:
#!/bin/bash
main() {
read -r -p "Input string: "
echo "User input: $REPLY"
}
if [ "$1" = "--log" ]; then
# If the first argument is "--log", shift the arg
# out and run main
shift
main "$#"
else
# If run without log, re-run this script within a
# script command so all script I/O is logged
script -q -c "$0 --log $*" test.log
fi
Unfortunately, you can't pass a function to script -c which is why the double-call is necessary in this method.
If it's acceptable to have two scripts, you could also have a user-facing script that just calls the non-user-facing script with script:
script_for_users.sh
--------------------
#!/bin/sh
script -q -c "/path/to/real_script.sh" <log path>
real_script.sh
---------------
#!/bin/sh
<Normal business logic>
It's simpler:
#! /bin/bash
tee ~/log | your_script
The wonderful thing is your_script can be a function, command or a {} command block!

Bash: exported variable not loaded in sh script

I have the following test.sh script:
#!/bin/sh
echo "MY_VARIABLE=$MY_VARIABLE"
Well, if I execute the following:
export MY_VARIABLE=SOMEVALUE
/bin/bash test.sh
it prints:
MY_VARIABLE=
Why the MY_VARIABLE is not read in the test.sh script?
You can reproduce the context here using the following script:
touch test.sh
chmod a+x test.sh
echo "#!/bin/sh" >> test.sh
echo "echo "MY_VARIABLE=$MY_VARIABLE"" >> test.sh
export MY_VARIABLE=something
/bin/bash test.sh
In your script to create the context, the line
echo "echo "MY_VARIABLE=$MY_VARIABLE"" >> test.sh
creates the following line in test.sh:
echo MY_VARIABLE=
if MY_VARIABLE was unset before. The expansion of $MY_VARIABLE is done in the shell that prepares your context.
If you use single quotes
echo 'echo "MY_VARIABLE=$MY_VARIABLE"' >> test.sh
the script test.sh contains the correct line
echo "MY_VARIABLE=$MY_VARIABLE"
and prints MY_VARIABLE=something as expected.
Everything works well but if you want your parent process to keep environment update, you must source your script:
source test.sh
Otherwise, changes will only have effect during the execution of your script.
You can consider it the same as sourcing your ~/.bashrc file.

How to pass argument in bash pipe from terminal

i have a bash script show below in a file called test.sh
#!/usr/bin/env bash
echo $1
echo "execution done"
when i execute this script using
Case-1
./test.sh "started"
started
execution done
showing properly
Case-2
If i execute with
bash test.sh "started"
i'm getting the out put as
started
execution done
But i would like to execute this using a cat or wget command with arguments
For example like.
Q1
cat test.sh |bash
Or using a command
Q2
wget -qO - "url contain bash" |bash
So in Q1 and Q2 how do i pass argument
Something simlar to this shown in this github
https://github.com/creationix/nvm
Please refer installation script
$ bash <(curl -Ls url_contains_bash_script) arg1 arg2
Explanation:
$ echo -e 'echo "$1"\necho "done"' >test.sh
$ cat test.sh
echo "$1"
echo "done"
$ bash <(cat test.sh) "hello"
hello
done
$ bash <(echo -e 'echo "$1"\necho "done"') "hello"
hello
done
You don't need to pipe to bash; bash runs as standard in your terminal.
If I have a script and I have to use cat, this is what I'll do:
cat script.sh > file.sh; chmod 755 file.sh; ./file.sh arg1 arg2 arg3
script.sh is the source script. You can replace that call with anything you want.
This has security implications though; just running an arbitrary code in your shell - especially with wget where the code comes from a remote location.

Bash script not running in Ubuntu

I'm getting started with bash scripting and made this little script following along a short guide but for some reason when I run the script with sh myscript I get
myscript: 5: myscript: 0: not found running on ubuntu 12.04
here is my script below I should at least see the echo message if no args are set:
#!/bin/bash
#will do something
name=$1
username=$2
if (( $# == 0 ))
then
echo "##############################"
echo "myscript [arg1] [arg2]"
echo "arg1 is your name"
echo "and arg2 is your username"
fi
var1="Your name is ${name} and your username is ${username}"
`echo ${var1} > yourname.txt`
`echo ${var1} > yourname.txt`
Get rid of the backticks.
echo ${var1} > yourname.txt
...for some reason when I run the script with sh myscript...
Don't run it that way. Make the script executable and run it directly
chmod +x myscript
./script
(or run with bash myscript explicitly).
It looks like that expression will work in bash but not in sh. As others pointed out change it to executable, make sure your shebang line is using bash and run it like this:
./myscript
If you want to run it with sh then it is complaining about line 5. Change it to this and it will work in /bin/sh.
if [ $# -ne 0 ]
Check out the man page for test.
Also you don't need the backticks on this line:
echo ${var1} > yourname.txt

bash: problem running command with quotes

In answering another question I created the following script bash script:
#!/bin/bash
files1=( file1.txt file2.txt file3.txt )
files2=( file1_.txt file2_.txt file3_.txt )
cmd="vim -c 'set diffopt=filler,vertical' -c 'edit ${files1[0]}' -c 'diffsplit ${files2[0]}' "
echo $cmd
for i in {1..2}; do
cmd="${cmd} -c 'tabe ${files1[i]}' -c 'diffsplit ${files2[i]}' "
done
#$cmd
echo $cmd
the problem is that if I try to run
$cmd
in the end of the script I get errors, but if I just use echo $cmd and then copy and paste in the command line it works just fine.
Any ideas what I am doing wrong?
Thanks.
Use:
eval $cmd
So that the variables within the expression are expanded before execution.
BASH FAQ entry #50: "I'm trying to put a command in a variable, but the complex cases always fail!"

Resources