2

I want to write a script that will run a certain commands on my subdirectories with names containging or rather end with some strings, say, *-nom1, *-nom2, *-nom3. i.e.

for dir in $(subs)
do
   // do something in this dir
done

my question is, would this be the way to list my sub-directories, if not what's the best way to do it:

subs = find -maxdepth 2 -type d -name '*-nom1'
&& find -maxdepth 2 -type d -name '*-nom2' 
&& find -maxdepth 2 -type d -name '*-nom3'

I can test it on my Ubuntu terminal and it seems to work.

my script will be running on Debian if that helps.

Gilles 'SO- stop being evil'
  • 807,993
  • 194
  • 1,674
  • 2,175
rethabile
  • 123
  • 4

2 Answers2

1

You can combine tests in find with -o standing for "or"; the implicit operator between tests is "and". For example:

subs="$(find -maxdepth 2 -type d \( \
  -name "*-nom1" -o -name "*-nom2" -o -name "*-nom3" \
\) )"
for d in $subs ; do
  ... do something with "$d" ...
done

The parantheses around `-name "-nom1" -o -name "-nom2" -o "*-nom3" need to be quoted because they are reserved words for the shell.

Now, as don_crissti remarks in a comment, the general recommendation is to avoid capturing the output of find, for two reasons; first, because file names may contain spaces and newlines and special characters and son on; and second, because find by its very nature loops over the results. The better idiom is to use the implicit loop in find; see Why is looping over find's output bad practice and the associated discussion:

find -maxdepth 2 -type d \( \
  -name "*-nom1" -o -name "*-nom2" -o -name "*-nom3" \
\) -exec \
  ... do something with '{}' ...
\;
AlexP
  • 10,217
  • 32
  • 41
  • Right. I will ammend the answer to include a brief explanation. – AlexP Nov 25 '16 at 21:11
  • hi @AlexP, I would like to generate a new directory using the last part of the directory. i.e. `basename {}`. doing this seems not to work `$pwd\somdir\basename {}` – rethabile Nov 28 '16 at 09:33
  • "Generate" is an ambiguous word. Do you want to make a new directory? Where? Directories are made by `mkdir`. – AlexP Nov 28 '16 at 09:39
  • sorry for being ambiguous. To be specific i need to run `dotnet publish` (https://docs.microsoft.com/en-us/dotnet/articles/core/tools/dotnet-publish), specifying the `--output` directory as `$pwd/publish/(basename {})`. the command will create the output directory if it doesn't exist. i.e. `dotnet publish {} -configuration release --output $pwd/publish/(basename {})` – rethabile Nov 28 '16 at 11:01
  • `MakeDirIfNotExisting () { [ -d "./publish/$(basename "$1")" ] || mkdir "./publish/$(basename "$1")" ; }` – AlexP Nov 28 '16 at 11:13
  • i meant i don't need to `mkdir` the directory. I just need to specify it, and `dotnet` command will create it if it doesn't exists. – rethabile Nov 28 '16 at 13:04
1

Two things I can think of

  1. Combine three find invocations into one

    find -maxdepth 2 -type d \( -name '*-nom1' -o -name '*-nom2' -o -name '*-nom3' \)
    
  2. Use find's ability to execute commands to avoid the external for loop

    find -maxdepth 2 -type d \( -name '*-nom1' -o -name '*-nom2' -o -name '*-nom3' \) \
    -exec sh -c 'for d; do cd "$d"; cmd1; cmd2; cmd3; ...; done' sh {} + 
    
iruvar
  • 16,515
  • 8
  • 49
  • 81