Re: bash Shell Scripting Question

2012-09-20 Thread Polytropon
On Thu, 20 Sep 2012 11:16:40 +0200, Jan Henrik Sylvester wrote:
> On 09/20/2012 04:29, Polytropon wrote:
> > Correct. You could use different approaches which may or may
> > not fail due to the directory names you will encounter (like
> > directories with spaces or special characters).
> >
> > #!/bin/sh
> > for DIR in `ls -LF | grep \/`; do
> > cd ${DIR}
> > # do stuff
> > done
> >
> > Or you can use piping:
> >
> > #!/bin/sh
> > ls -LF | grep \/ | while read DIR; do
> > cd ${DIR}
> > # do stuff
> > done
> >
> > I'm quite confident there are even more elegant and fault-
> > tolerant solutions. You would maybe have to tweak the ls
> > command or play with IFS (space or newline).
> 
> Even if you start quoting "${DIR}", the first one will fail at least for 
> names containing spaces, the second one at least for names starting with 
> spaces. As you said, you would have to change IFS to maybe slash and 
> newline, assuming that you do not have names containing newlines, in 
> which case the approach cannot work.

You are fully correct: In order to create an iterator that
provides "valid" directory names, even for the cases where
"unusual" characters (which are _valid_ characters for file
names and directory names) are included, is not trivial.

Allow me to point to those two articles which mention different
approaches and show why they are wrong. :-)

David A. Wheeler:
Filenames and Pathnames in Shell: How to do it correctly
http://www.dwheeler.com/essays/filenames-in-shell.html

David A. Wheeler:
Fixing Unix/Linux/POSIX Filenames:
Control Characters (such as Newline), Leading Dashes, and Other Problems
http://www.dwheeler.com/essays/fixing-unix-linux-filenames.html



> I understand that you want all directories and links to directories not 
> starting with a period. How about trying all files not starting with a 
> period and skipping the non directories:
> 
> #!/bin/sh
> for DIR in *
> do
>  cd "$DIR" >/dev/null 2>&1 || continue
>  pwd
>  cd - > /dev/null
> done
> 
> This one works with names containing spaces or even newlines and does 
> not even need to spawn external commands or subshells. It may have other 
> caveats, though.

It will work - it delegates resolving * to the shell instead
of having a different program (ls | grep, find) doing that.





-- 
Polytropon
Magdeburg, Germany
Happy FreeBSD user since 4.0
Andra moi ennepe, Mousa, ...
___
freebsd-questions@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-questions
To unsubscribe, send any mail to "freebsd-questions-unsubscr...@freebsd.org"


Re: bash Shell Scripting Question

2012-09-20 Thread Martin McCormick
Many thanks! The for loop was what was needed.

Polytropon writes:
> Just a sidenote: If you're not using bash-specific functionality
> and intend to make your script portable, use #!/bin/sh instead.

I always start out that way for that very reason. I needed some
random number functions and arithmetic for another part of the
script so I ended up going to bash.

> > while read dirname; do
> 
> Attention: "dirname" (/usr/bin/dirname) is a binary!

You are so correct!  Thank you.

Continuing;

> Correct. You could use different approaches which may or may
> not fail due to the directory names you will encounter (like
> directories with spaces or special characters).

In this application, all the directories will be
non-problematic, but point well taken.

> 
> #!/bin/sh
> for DIR in `ls -LF | grep \/`; do
> cd ${DIR}
> # do stuff
> done

That works perfectly. Again many thanks.
___
freebsd-questions@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-questions
To unsubscribe, send any mail to "freebsd-questions-unsubscr...@freebsd.org"


Re: Re: bash Shell Scripting Question

2012-09-20 Thread Jan Henrik Sylvester

On 09/20/2012 04:29, Polytropon wrote:

Correct. You could use different approaches which may or may
not fail due to the directory names you will encounter (like
directories with spaces or special characters).

#!/bin/sh
for DIR in `ls -LF | grep \/`; do
cd ${DIR}
# do stuff
done

Or you can use piping:

#!/bin/sh
ls -LF | grep \/ | while read DIR; do
cd ${DIR}
# do stuff
done

I'm quite confident there are even more elegant and fault-
tolerant solutions. You would maybe have to tweak the ls
command or play with IFS (space or newline).


Even if you start quoting "${DIR}", the first one will fail at least for 
names containing spaces, the second one at least for names starting with 
spaces. As you said, you would have to change IFS to maybe slash and 
newline, assuming that you do not have names containing newlines, in 
which case the approach cannot work.


I understand that you want all directories and links to directories not 
starting with a period. How about trying all files not starting with a 
period and skipping the non directories:


#!/bin/sh
for DIR in *
do
cd "$DIR" >/dev/null 2>&1 || continue
pwd
cd - > /dev/null
done

This one works with names containing spaces or even newlines and does 
not even need to spawn external commands or subshells. It may have other 
caveats, though.


Cheers,
Jan Henrik
___
freebsd-questions@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-questions
To unsubscribe, send any mail to "freebsd-questions-unsubscr...@freebsd.org"


Re: bash Shell Scripting Question

2012-09-19 Thread Polytropon
On Wed, 19 Sep 2012 21:03:11 -0500, Martin McCormick wrote:
>   I just discovered a knowledge deficiency on my part that
> I can't seem to resolve.
> 
>   If one writes a loop of the following form:
> 
> #!/usr/local/bin/bash 

Just a sidenote: If you're not using bash-specific functionality
and intend to make your script portable, use #!/bin/sh instead.



> ls -LF |grep \/ >/tmp/files
> while read dirname; do

Attention: "dirname" (/usr/bin/dirname) is a binary!



> cd $dirname
> #Do whatever commands to be repeated in each directory.
> done < /tmp/files
> 
>   This works quite well but it is shall we say sloppy
> because it creates a file that then must be cleaned up and its
> name needs to be made unique, etc.

Correct. You could use different approaches which may or may
not fail due to the directory names you will encounter (like
directories with spaces or special characters).

#!/bin/sh
for DIR in `ls -LF | grep \/`; do
cd ${DIR}
# do stuff
done

Or you can use piping:

#!/bin/sh
ls -LF | grep \/ | while read DIR; do
cd ${DIR}
# do stuff
done

I'm quite confident there are even more elegant and fault-
tolerant solutions. You would maybe have to tweak the ls
command or play with IFS (space or newline).



>   The standard output of the `ls -LF |grep \/` command
> needs to look like a file and all should be well. I thought the
> < redirection would pickup the standard output.

No, the > and < redirections basically operate on files,
while pipes redirect strandard output to standard input.
So for example,

somecommand < /tmp/somefile

refers to a file that has to exist, while

somecommand < `someothercommand`

does not take someothercommand's output (stdout), but instead
interprets it as a file specification and then reads from that
files (if existing).




-- 
Polytropon
Magdeburg, Germany
Happy FreeBSD user since 4.0
Andra moi ennepe, Mousa, ...
___
freebsd-questions@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-questions
To unsubscribe, send any mail to "freebsd-questions-unsubscr...@freebsd.org"


Re: bash Shell Scripting Question

2012-09-19 Thread Mihai Donțu
On Wed, 19 Sep 2012 21:03:11 -0500 Martin McCormick wrote:
> #!/usr/local/bin/bash 
> ls -LF |grep \/ >/tmp/files
> while read dirname; do
> cd $dirname
> #Do whatever commands to be repeated in each directory.
> done < /tmp/files
> 

How about:

   ls -LF | grep \/ | while read dirname; do
   cd $dirname
   # do stuff
   done

or:

   find . -maxdepth 1 -type d | while read dirname; do
   cd $dirname
   # do stuff
   done

or even:

   find . -maxdepth 1 -type d ! -name ".*" | while read dirname; do
   cd $dirname
   # do stuff
   done

-- 
Mihai Donțu
___
freebsd-questions@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-questions
To unsubscribe, send any mail to "freebsd-questions-unsubscr...@freebsd.org"


bash Shell Scripting Question

2012-09-19 Thread Martin McCormick
I just discovered a knowledge deficiency on my part that
I can't seem to resolve.

If one writes a loop of the following form:

#!/usr/local/bin/bash 
ls -LF |grep \/ >/tmp/files
while read dirname; do
cd $dirname
#Do whatever commands to be repeated in each directory.
done < /tmp/files

This works quite well but it is shall we say sloppy
because it creates a file that then must be cleaned up and its
name needs to be made unique, etc.

The standard output of the `ls -LF |grep \/` command
needs to look like a file and all should be well. I thought the
< redirection would pickup the standard output.

Thanks for ideas.

Martin McCormick
___
freebsd-questions@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-questions
To unsubscribe, send any mail to "freebsd-questions-unsubscr...@freebsd.org"