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.

rethabile
  • 123

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,455
  • 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,725