LinuxQuestions.org
Download your favorite Linux distribution at LQ ISO.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Linux Forums > Linux - Newbie
User Name
Password
Linux - Newbie This 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


Reply
  Search this Thread
Old 05-04-2012, 12:35 PM   #1
lleb
Senior Member
 
Registered: Dec 2005
Location: Florida
Distribution: CentOS/Fedora/Pop!_OS
Posts: 2,983

Rep: Reputation: 551Reputation: 551Reputation: 551Reputation: 551Reputation: 551Reputation: 551
BASH array question


Below is the bash -xv output of a section of code that i seem to have messed up.

Code:
copysys
+ copysys
+ SYSFILES='/etc/hosts /etc/exports /etc/dhcpd.conf /etc/resolv.conf /etc/cups/printers.conf /etc/sysconfig/static-routes /etc/sysconfig/network-scripts-ifcfg-eth* /opt/ltsp/i386/etc/lts.conf /etc/fstab /etc/xinetd/net.conf /etc/samba/smb.con'
+ echo 'Copy system files to user directory.'
+ for f in '"${SYSFILES[@]}"'
+ cp /etc/hosts /etc/exports /etc/dhcpd.conf /etc/resolv.conf /etc/cups/printers.conf /etc/sysconfig/static-routes '/etc/sysconfig/network-scripts-ifcfg-eth*' /opt/ltsp/i386/etc/lts.conf /etc/fstab /etc/xinetd/net.conf /etc/samba/smb.con /usr/rx30 '$'
cp: target `$' is not a directory
this is the function copysys

Code:
### Function to copy system files to $HOME
######################################

copysys ()

{
        SYSFILES="/etc/hosts /etc/exports /etc/dhcpd.conf /etc/resolv.conf /etc/cups/printers.conf /etc/sysconfig/static-routes /etc/sysconfig/network-scripts-ifcfg-eth* /opt/ltsp/i386/etc/lts.conf /etc/fstab /etc/xinetd/net.conf /etc/samba/smb.con"
        echo "Copy system files to user directory." >> ${logname}

for f in "${SYSFILES[@]}"
do
cp $f ${HOMEDIR} $>/dev/null
done

}
the HOMEDIR="$HOME" for those who will ask. yes i am running this as user, and yes i have already setup visudo properly. i can make the copy manually with no issue.

Thanks in advance for the help.
 
Old 05-04-2012, 12:39 PM   #2
suicidaleggroll
LQ Guru
 
Registered: Nov 2010
Location: Colorado
Distribution: OpenSUSE, CentOS
Posts: 5,573

Rep: Reputation: 2142Reputation: 2142Reputation: 2142Reputation: 2142Reputation: 2142Reputation: 2142Reputation: 2142Reputation: 2142Reputation: 2142Reputation: 2142Reputation: 2142
It looks like the "$" in front of the >/dev/null is what's messing things up. I'm not sure what you're trying to accomplish there, maybe you meant to use a "&"?
 
1 members found this post helpful.
Old 05-04-2012, 01:55 PM   #3
lleb
Senior Member
 
Registered: Dec 2005
Location: Florida
Distribution: CentOS/Fedora/Pop!_OS
Posts: 2,983

Original Poster
Rep: Reputation: 551Reputation: 551Reputation: 551Reputation: 551Reputation: 551Reputation: 551
hmm my reply thanking you disappeared... You are correct i wanted the &, not the $. a 2nd pair of eyes is often a great help.
 
Old 05-04-2012, 03:10 PM   #4
David the H.
Bash Guru
 
Registered: Jun 2004
Location: Osaka, Japan
Distribution: Arch + Xfce
Posts: 6,852

Rep: Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037
That's not the only problem with this code.

Code:
SYSFILES="/etc/hosts /etc/exports /etc/dhcpd.conf /etc/resolv.conf /etc/cups/printers.conf /etc/sysconfig/static-routes /etc/sysconfig/network-scripts-ifcfg-eth* /opt/ltsp/i386/etc/lts.conf /etc/fstab /etc/xinetd/net.conf /etc/samba/smb.con"
This is not an array. It's just a single scalar variable. The only reason the code is working at all is because of the unquoted $f variable later on. It allows the list (there's only one entry so the only function of the loop is to copy the first variable into the second) to be word-split by the shell.

So the cp command is actually executed as this:

Code:
cp /etc/hosts /etc/exports ... etc ... ${HOMEDIR}
You can see it in your debugging output. If any of those filenames had spaces in them (including $HOMEDIR), they'd get broken up in the wrong places, and you'd get "filename not found" errors.

The proper array-setting syntax is "array=( <wordlist> )". Be sure to put quotes around any string that has spaces or globbing patterns it too (such as your "/etc/sysconfig/network-scripts-ifcfg-eth*" here, unless you actually want it to expand into the full list of files first. That may or may not be what you want).


It might also be a good idea to declare the array local to the function, unless you need to use it elsewhere in the script. (But then again, if you did, you'd probably set it outside the function anyway, right?)


Code:
echo "Copy system files to user directory." >> ${logname}

cp $f ${HOMEDIR} $>/dev/null
In addition to the syntax error discussed before, variable expansions should always be quoted, unless you know exactly what you are doing and have a very good reason for leaving them off. Again, as shown, this is to protect the output from word-splitting and filename expansion.


This is a vital concept in scripting, so read, and reread until you fully understand, these links:
http://mywiki.wooledge.org/Arguments
http://mywiki.wooledge.org/WordSplitting
http://mywiki.wooledge.org/Quotes


Finally, a suggestion about style. Clean, consistent formatting makes code readable and more easily debuggable. Indent all your sub-commands (meaning the function contents and the for loop in this case), and clearly separate logical sections with whitespace. Add comments anywhere the code isn't completely obvious (and remember, what seems obvious to you now will not be so a year or so down the line).

Many people also think that it's more readable to place the "do/then" keywords on the same line as the "for/while/until/if" keywords, as it more clearly separates the outside block from the inside block.

In addition, environment variables are generally upper-case, so while not critical, it's good practice to keep your own user variables in lower-case or mixed-case, to help differentiate them. And using the full bracket syntax when you don't need it does nothing but clutter up the script. I recommend leaving them off.


With all this taken into account, I think the above function should probably look more like this:

Code:
copysys () {

	local -a sysfiles=(
		/etc/hosts  /etc/exports  /etc/dhcpd.conf
		/etc/resolv.conf  /etc/cups/printers.conf
		/etc/sysconfig/static-routes
		'/etc/sysconfig/network-scripts-ifcfg-eth*'
		/opt/ltsp/i386/etc/lts.conf  /etc/fstab
		/etc/xinetd/net.conf /etc/samba/smb.con
		)

	echo "Copy system files to user directory." >> "$logname"

	for f in "${sysfiles[@]}"; do

		cp "$f" "$homedir" &>/dev/null

	done

}
Actually, as shown before, the for loop isn't really necessary. You can copy the whole list at once. I'd use cp's -t option for maximum safety.

Code:
cp -t "$homedir" "${sysfiles[@]}"

Actually #2, it's not usually good form to store data inside a script. It would be better to import the list values from a separate file or the command line. this would allow you to update the list as necessary without worrying about editing the script itself, and possibly breaking something in it. Or at the very least put all of your user settings at the top of the script, so you don't have to hunt through the code to change things.

Last edited by David the H.; 05-04-2012 at 03:20 PM. Reason: minor fixes
 
  


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
Bash array question edwardcode Programming 14 08-29-2011 06:54 AM
Bash Array - Probably an easy question jon_k Programming 3 03-10-2009 12:08 PM
Bash array question MinnesotaDrifter Linux - Newbie 3 01-21-2009 12:11 AM
bash array question dazdaz Programming 8 11-21-2008 11:40 AM
Bash array question krock923 Programming 3 06-22-2006 11:39 AM

LinuxQuestions.org > Forums > Linux Forums > Linux - Newbie

All times are GMT -5. The time now is 01:31 AM.

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