On Thu, Oct 11, 2012 at 08:01:40PM -0700, Tinni wrote: > I am very new to the shell scripting.. Need some pointers for getting the > return value in shell scripting.
"Return value" is an integer from 0 to 255. That's not what you want. > I want the values ( db_host_user, db_host, ORACLE_SID) should be returned > from the clonesel to test1.sh > > If i set the script inside the test1.sh as > > val=`ssh remoteserver '/bin/sh clonesel' `, So, you're trying to retrieve 3 separate (string?) values from a remote system. > In the remote server , the script clonesel is as follows: > > > #!/bin/bash > > echo > echo -e "\e[1;31m\tSetup Oracle Environments \e[0m" > echo -e "\t--------------------------" All of that extraneous output and terminal formatting is going to get in the way. Your best bet would be to write a separate script and run that instead of running this clonesel thing. > echo > echo > echo -en "\e[1;32m\tType DB OS User Name :\e[0m" > read db_host_user Wait... clonesel is interactive? You were planning to run an interactive script on a remote system to prompt the user for information and then send that information back to the calling script on the local system? That doesn't make much sense. Why not simply prompt the user for the information on the local system and skip the ssh call altogether? (Another problem you had is that the clonesel script contains bash-specific code, and even begins with a #!/bin/bash shebang, but you explicitly invoked it using /bin/sh.) ----------------------- Let's suppose you were starting from scratch and didn't have all of this crazy code in place, and you wanted to retrieve three string values from a remote system. This is perhaps a completely different problem from the one you asked, but it might be helpful if you can rephrase your original problem a bit. Now, a script can read streams of data, and you can embed three strings into a single stream of data. The trick is to be able to separate them into the component strings on the receiving end. The most common way to do that is to use some sort of delimiter between the strings. The delimiter must be a character, or a sequence of characters, which is guaranteed not to appear within the strings. Let's assume that we can use a newline character as the delimiter. Then, you could do it this way: #!/bin/bash { IFS= read -r string1 IFS= read -r string2 IFS= read -r string3 } < <( ssh "$user"@"$host" bash <<'EOF' source ~oracle/.whatever || exit echo "$thing1"; echo "$thing2"; echo "$thing3" EOF ) Obviously you would substitute the appropriate variable names, and the appropriate filenames or whatever steps you need to take to get the remote shell into a state where it can produce the information you need. I realize that's probably a huge number of new features all at once, so let me break this down into pieces and explain it, and why it's done this way. The first part, you already know about: #!/bin/bash This ensures that our script will be run under bash, and not under sh. This is necessary because we are using bash syntax that will not work under sh. This also means that the script must be invoked as ./script or as "bash script", NOT as "sh script" or "/bin/sh script". The second part is a command grouping: { command one command two ... } This grouping means that any redirections applied to the group are inherited by all of the commands in the group. It also *does not* use a subshell. If we had used parentheses instead of curly braces then bash would have created a subshell for the commands, and the read commands would have been performed inside that subshell. That is not what we want, because when the subshell exits, all the variables set by all the read commands will be gone. Next we have several read commands: IFS= read -r string1 IFS= read -r string2 IFS= read -r string3 Each of these reads one line of data from stdin (terminated by a newline character), and puts the contents of that line into the variable named after the -r. The "IFS=" part ensures that there will be no stripping of leading/trailing spaces. The "-r" part ensures that there will be no special handling of backslash characters in the data. We just want the actual payload, with NO interpretation by the shell, and both IFS= and -r are required to ensure that. Because the reads are grouped together, they all share a single input. The first one will read a line from that input, and then the second one will read the NEXT LINE from that input, and so on. Next we have a redirection which is applied to a group: { ... } < foo The "<" character by itself means that stdin (standard input) is being redirected from foo. The placement after the closing "}" of the group means that the redirection applies to the entire group. Next we have a process substitution: <( some command ) This is a special bash feature (and the reason we needed #!/bin/bash). It creates a virtual filename that can be used as an argument to a program or a target of a redirection. We're using it as the target of a redirection, which is why we have this: < <( some command ) There MUST be a space between the redirection "<" and the process substitution "<(". You don't actually need spaces between "<(" and the command, or between the command and ")". Those were just inserted for clarity. Next we have an ssh command: ssh "$user"@"$host" command This causes "command" to be executed on the remote host "$host" as user "$user". The details of ssh are beyond the scope of this mailing list, so hopefully you know the basics there. In our case, "command" is bash. We are telling ssh to run bash on the remote system. That instance of bash will read commands from its own stdin (since we didn't give it any arguments). Next we have a here document: ssh ... <<'EOF' ... EOF This is a special kind of redirection which creates stdin for a command using lines of text from the script itself, rather than from a separate file. The payload which is sent to the command's stdin will be the lines of text in between <<'EOF' and EOF. Since we have 'quotes' around 'EOF', the script will NOT perform any substitutions within those lines. That's what we want, because we want the lines of text to be interpreted on the REMOTE system, not on the local system. Inside the here document, we have the commands that the remote bash will execute for us: source ~oracle/.whatever || exit echo "$thing1"; echo "$thing2"; echo "$thing3" Now, here I am assuming a thing which may not be true in your case. I am assuming that the variables you require can be instantiated within a bash shell by sourcing some file in a fixed location. If that isn't true for you -- if you really must prompt a user for them -- then you should throw away ALL of the code you have, and throw away this email as well, and just start from scratch, and prompt the user for the data on the local system. But if there is such a file on the remote system (perhaps ~oracle/.profile), then the remote bash will source it (will read the commands inside it and execute them as if they had been typed by a user), and then the variables we require will become available. We use three separate echo commands to write the variables to stdout. Echo adds a newline at the end -- again, that is what we want, because we designed this so that there would be newline delimiters at the end of each variable, because that is what "read" expects. The remote bash will write a single stream of data to its stdout. This stream will be a variable, then a newline, then another variable, then a newline, then the third variable, then a newline. The process substitution + redirection takes stdout from the command(s) inside <(...) and makes it available as stdin to the group of read commands. So, the three reads will see that data stream (three variables with newlines) and will operate on that. Once this chunk of code has finished executing, you will be left with three shell variables on the local system, containing the three pieces of data you wanted from the remote system. Then it's up to you to do whatever's necessary with those data.