LinuxQuestions.org
Share your knowledge at the LQ Wiki.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 11-28-2006, 05:48 AM   #1
dakensta
Member
 
Registered: Jun 2003
Location: SEUK
Distribution: Debian & OS X
Posts: 194

Rep: Reputation: 35
Bash Command Substitution


I am having a few problems with scripting a loop using command substitution, specifically with string expansion.

I want to run a query through a number of mysql hosts, but, I think, building the command as a string means that the arguments are presented as a single string rather than multiple strings

Specifically:
Code:
user=username
pass=password
hosts=(host1 host2 host3 host4)
for h in ${hosts@}
do
    res=$(mysql -u ${user} -p${password} -h ${h} -e "SELECT blah FROM bleh")
    # Do stuff with ${res}
done
This is not the only time this has come up and regardless of the command the output is always the commands help produced in case of incorrect arguments.

What I want to know is how to correctly build commands as strings and then pass them on for command substitution in a shell script. I have tried all sort of combinations but to no avail.
 
Old 11-28-2006, 06:00 AM   #2
jschiwal
LQ Guru
 
Registered: Aug 2001
Location: Fargo, ND
Distribution: SuSE AMD64
Posts: 15,733

Rep: Reputation: 682Reputation: 682Reputation: 682Reputation: 682Reputation: 682Reputation: 682
I looks like you have a few errors in the start of the script.

Code:
user=$username            # maybe you want an argument instead as in "user=$1" and "pass=$2"
pass=$password
hosts=(host1 host2 host3 host4)
for h in ${hosts[@]}
You are putting a string of hosts into the variable "hosts" and then converting it back into a string of hosts. You might want to do this if you will use ${hosts} again, or if you want the list of hosts near the top of a longer script so you can find and edit it easier. But for a 3 line script, you could just use:
for host in host1 host2 host3 host4; do
...
done

You assigned $password to $pass but used $password in the sql line.

You can also build the entire command in a variable, let's call it mysqlcmd. Then a line like:
${mysqlcmd}
will execute the cmd.

Last edited by jschiwal; 11-28-2006 at 06:17 AM.
 
Old 11-29-2006, 03:46 AM   #3
dakensta
Member
 
Registered: Jun 2003
Location: SEUK
Distribution: Debian & OS X
Posts: 194

Original Poster
Rep: Reputation: 35
The script was only an off the cuff example, I know it is not right, just trying to illustrate the bit I don't understand.

Quote:
You can also build the entire command in a variable, let's call it mysqlcmd. Then a line like:
${mysqlcmd}
will execute the cmd.
But this doesn't store the output in a variable, which is why I am using command substitution and furthermore, still does not correctly execute the command

Here is a complete example:
Code:
for i in 1 2
do
  daysAgo="'${i} days ago'" 
  echo ${daysAgo}                  # 1. Output is: '1 days ago'
  cmd="date --date="${daysAgo}" +%d/%m/%Y"
  echo ${cmd}                        # 2. Output is: date --date='1 days ago' +%Y-%m-%d
  ${cmd}                                # 3. Output is: date: too many non-option arguments: ago'
  $(${cmd})                            # 4. Output is: date: too many non-option arguments: ago'
done
Copy and pasting the output at 2. (from echo ${cmd}) into the command line directly successfully executes the command (i.e. the string is correctly built), giving 28/11/2006
 
Old 11-29-2006, 11:57 AM   #4
fvu
LQ Newbie
 
Registered: Nov 2006
Distribution: Ubuntu 7.10
Posts: 28

Rep: Reputation: 15
eval does the trick:
Code:
#!/bin/bash
for i in 1 2; do
    cmd="date --date=\"$i days ago\""
    eval $cmd
done
See also: Uwe Waldmann - A Guide to Unix Shell Quoting - Common misconceptions
Before the shell executes a command, it performs the following operations (check the manual for details):

1. Syntax analysis (Parsing)
2. Brace expansion
3. Tilde expansion
4. Parameter and variable expansion
5. Command substitution
6. Arithmetic expansion
7. Word splitting
8. Filename expansion
9. Quote removal

It is important to realize that parsing takes place before parameter and command substitution. The result of a step n is subject to the next steps (n+), but the preceding steps (n-) are not re-executed. In other words: after for example variable expansion (step 4) the result is not re-parsed (step 1).

In the example of the command:
$cmd # cmd="date --date=\"1 days ago\""
the command date --date=\"$i days ago\" is the result of variable expansion (step 4). Quote removal (step 9) removes the backslashes and turns the command into date --date="$i days ago". But since parsing (step 1) already has taken place, "1 days ago" is not seen as 1 argument but as 3 separate arguments: "1, days and ago", which gives you the error message:
date: extra operand `ago"'
Try `date --help' for more information.
To force one more run through the parsing/expansion procedure, use:
eval $cmd
Now first $cmd is expanded (steps 1-9) to date --date="1 days ago". Then eval causes the expanded string to be re-parsed again (steps 1-9), resulting in the correct command:
date --date="1 days ago"
Wed Nov 29 08:11:46 CET 2006
Freddy Vulto
http://fvue.nl/wiki/Bash

Last edited by fvu; 12-01-2006 at 02:20 PM.
 
Old 11-30-2006, 10:53 AM   #5
dakensta
Member
 
Registered: Jun 2003
Location: SEUK
Distribution: Debian & OS X
Posts: 194

Original Poster
Rep: Reputation: 35
Thank you very much.

An excellent answer that has significantly helped fill gaps in my understanding.
 
Old 11-30-2006, 03:10 PM   #6
gnashley
Amigo developer
 
Registered: Dec 2003
Location: Germany
Distribution: Slackware
Posts: 4,928

Rep: Reputation: 612Reputation: 612Reputation: 612Reputation: 612Reputation: 612Reputation: 612
Try this:
hosts="host1 host2 host3 host4"
for h in $hosts
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Varible substitution in Bash script RonV Linux - Newbie 2 06-04-2006 12:11 PM
Bash variable substitution daYz Programming 3 04-14-2006 01:16 PM
command substitution: ^ rhxk Linux - General 2 04-06-2006 09:51 AM
Bash Process Substitution joshholt Programming 4 10-11-2005 03:15 AM
bash assignments of commands substitution p0rtius Programming 6 07-03-2005 06:41 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 06:45 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration