Re: bash Shell Scripting Question
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
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
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
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
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
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"