[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: bash scripting question



Neal Lippman <nl@lippman.org> [2002-11-03 13:35:22 -0500]:
> Thanks. My "bug" here was using comma instead of space as the separator,
> and not realizing that the reason for x in {a,b,c,d...z} worked was
> because of the way the brace expansion was being done by the shell.

Ah, yes, csh style {one,two,three} expansion.  But not in a string.

> It isn't really the echo statement that is what I need. Actually, I have
> a database organized into subdirectories starting with letters of the
> alphabet (eg /data/A, /data/B, and so on) and within each subdirectory
> are further directories based on people's names. I use the alphabetical
> subdirectories to organize things so I don't have thousands of
> directories in /data.

A wise configuration.  Classic filesystems such as BSD FFS, and
similar like Ext2 and Ext3 have severe degradation problems when you
get around 40,000 files in one single directory.  Some filesystems
such as JFS (and I think, not sure, XFS and ReiserFS too) store
directies in B+ trees and are specifically designed to handle large
databases of files efficiently.  That is the draw of those newer
filesystems.

> The need for the iterator is so that I can scan
> through all the subdirectories, so I often use syntax like:
> 	for x in "A B C D ... Z"; do
> 		cd $x ;
> 		for y in *; do
> 			cd $y ;
> 			for z in *; do
> 				<do something which each data file>
> 			done
> 			cd ..
> 		done
> 		cd ..
> 	done
> I was just looking for a shortcut for typing the entire alphabet each
> time. Many of the operations are repeated, so I wrote scripts for them,
> but sometimes I just need to type the syntax by hand to do something,
> and it bothered me that I couldn't figure out the write bash syntax.

But you can.  If all of the directories are there and enumerated them
you can match them with another file glob.  You do something similar
with '*' in the above.  If A-Z are the only directories there then *
would work again.  Or you could be more specific using [A-Z].

	for x in [A-Z]; do
		cd $x ;
		for y in *; do
			cd $y ;
			for z in *; do
				<do something which each data file>
			done
			cd ..
		done
		cd ..
	done

But that is a lot of 'cd someplace' and loops.  I think they can be
collapsed.

	for x in [A-Z]/*/*; do
		cd $x ;
		<do something which each data file>
		cd ../../..
	done

I don't like having to remember to back out of the 'cd' and so
whenever possible I try to make it a single line cd and put it in to a
subshell.  The subshell will cd but the parent, this script will not.
When the subshell exits the parent will be at the same place it was
before and there is no possibility of getting your cd down dir and
your cd up dir actions mismatched.

	for x in [A-Z]/*/*; do
		(cd $x ; <do something which each data file> )
	done

> Of course, the smart thing is to write a script that takes the desired
> command as a parameter and executes the above loop with that command.

Yes, no, maybe.  Does the above collapse of syntax help?  Hope so.

Bob

Attachment: pgplXK5XthZ59.pgp
Description: PGP signature


Reply to: