Linux - NewbieThis Linux forum is for members that are new to Linux.
Just starting out and have a question?
If it is not in the man pages or the how-to's this is the place!
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
Use the output of the script as your data channel.
One way to pass information is to pipe data from one program to other.
Alternatively you can pick ouput to a variable with the syntax you just described.
e.g.
What you have to understand is that when a "command" is run in UNIX or Linux, it is highly isolated from its parent.
The rule is that is has no unexpected side effects. In Windows, if you start a command and the command changes your working directory, the working directory of the parent is also changed. But with a proper, isolated process model, the parent must specifically do something to allow the child to affect it.
The export verb in shell writing is actually used to add the variable to the list of variables that are exported to the child.
The typical way that you extract things from a child process is to have the child output them. Then you capture the output in one of several ways.
One way is simply to not start a child process. This is called "sourcing". For example, the login scripts affect the shell process that they run in. They can change the directory, or set variables. This is because the process interprets the script without starting a child process.
You can do the same thing, by prefacing the filename with a separate period.
Thus:
. path/to/file
indicates that the file (which must be in the same script language that it is being sourced into) is to be interpreted right there. Any variables that it sets and perhaps exports are set in the current shell's process, as for aliases and so forth. The directory changes stick.
Another possibility is that you can interpolate the output of the commands into other commands. For example, you can say
#! /bin/sh
echo this file contains $(wc -l < $0) lines and $(wc -c < $0) characters\
for a total of $(($(wc -l < $0) + $(wc -c $c < $0 )))
Which produces the output
this file contains 5 lines and 142 characters for a total of 147
So, how did that work? Well, it runs the wc command 4 rimes, always using the current file as an input. When you run the wc (word count) command, it outputs a number. This number is directly put into the current line, which is going to be arguments to echo. The second time, the output from the wc command is stuck into a mathematical expression, which is indicated by $(( )).
So $( ) brackets a command, and $(( )) brackets a numerical expression. We could also have done the command this way:
#! /bin/sh
a=`wc -l < $0`
b=`wc -c < $0`
echo this file contains $a lines and $b characters\
for a total of $((a+b))
and the output is
this file contains 6 lines and 119 characters for a total of 125
In this case, we use the backtic to bracket the commands that are to be executed. This allows us to grab the output of the command as a variable, which we can then use in other expressions. q#! /bin/sh
declare -a b
b=("$@")
set -- $( wc -lc < $0)
echo ${#b[*]} ${b[*]}
echo "this file (${b[0]}) contains ${1} lines and (${b[1]}) ${2} characters for a total of $(($1+$2))"
which, given this input puts this out:
/tmp/ex1 a b c d e
5 a b c d e
this file (a) contains 7 lines and (b) 183 characters for a total of 190
So, how did THIS work?
We first save the arguments that we are passed - we declare variable b as an array. The syntax I use thereupon makes a separate token for each element of the argument list. The double quotes are essential, as this means that if one of the arguments has characters in $IFS, it will not be subjected to word splitting. The parenthesis in the assignment say. "assign each word to a different element". So we have saved the arguments. The set command is the traditional way of breaking the output of a process by word and assigning it to separate variables, but it reuses the $n positionals, which is why I had to save them in the first place.
You can see the substitutions. This is the most general way to do this, and will work in shells other than bash. You might see it as a leftover from other scripts, which is why I present it. However, I also suggest that if you are only going to run your script under bash, this is the "right" way to do it.
#! /bin/sh
declare -a b
b=($( wc -lc < $0) )
echo "this file contains ${b[0]} lines and ${b[1]} characters for a total of $((b[0]+b[1]))"
this file contains 5 lines and 139 characters for a total of 144
Here, we simply use the ability of the assignment to run a command and break the output of the command into words. Each of those words are assigned to a separate array element. Then you can access those array elements.
This will be the fastest shell script. There are cheap operations in the shell, and expensive ones. The most expensive operations run commands. The less expensive operations just access files from within the shell, and the least expensive operations only access internal shell commands and variables. The last version only runs one external command, as opposed to the four external commands that the first version of this script ran, and that is a pain. For tis scripr it does not matter, but it will, someday. The use of $(( )) for mathematical work rather than expr will help, as will avoiding "if true" for "if [[ 1 ]]" since true, in this context, is an external command.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.