1

I am new and I have small problem and I couldn't solve it by myself. Here is the issue that I am faced with:

  • I am trying to find the files with spaces in their names.

    This part is working:

      find $(pwd) -type d |grep " "
    
  • Then I am using the awk to print whole file name and change it with desired group name "manually typing"

      find $(pwd) |grep " " |awk '{print "changegrp developers \""$0"\""}'
    
  • When I try to make group name developers as a variable, it is not really working as expected.

      find $(pwd) |grep " " |awk group="developers" '{print "changegrp group \""$0"\""}'
    

I really don't understand the syntax. how it is possible that manually typed group is working and when I make it a variable, it is working. I know that kind of things can give some headaches due to forgetting one single quote or double quotes etc.

Could you please point me out where I am making wrong?

learner
  • 13
  • 2

2 Answers2

2

To pass group into awk as a variable you need -v group="developers" and to have awk treat it as a variable (rather than a string literal) it needs to be outside the double quotes, like

awk -v group="developers" '{print "changegrp " group " \""$0"\""}'

However, you can likely avoid a lot of headaches by using something like

find . -type d -name '* *' -exec changegrp developers {} \;

or (if changegroup supports multiple file arguments - I am unfamiliar with the particular command)

find . -type d -name '* *' -exec changegrp developers {} +

See also

steeldriver
  • 81,074
  • Good night steeldriver, thank you for your answer. definitely your answer is the best one. To be honest, when I see the solution with the find exec combination. I said by myself, "why i thought that complicated? if I could do this operation with the simple find exec command. Anyway i forgot with the first command (with the awk) to add "| bash" to execute the awk command. Additionally, I could pass the argument to the find exec combination as well. I want to thank you again for your great time. Highly appreciated! Have a nice night. Now I can sleep better. :) – learner May 14 '20 at 01:39
  • print "changegrp " group " \""$0"\"" should be print "changegrp \047" group "\047 \047" $0 "\047" so it won't fail if $0 or group contains characters you don't want the shell interpreting (assuming you're generating a list of commands to be executed later by a shell). There should probably be a -- in there too between the command name and the arguments but that's probably overkill. – Ed Morton May 14 '20 at 13:45
1

Sidestepping both find and awk, and assuming you're interested in only directories (as per your first code snippet):

shopt -s globstar dotglob nullglob

for name in ./**/*' '*; do
    [[ -d $name ]] && [[ ! -L $name ]] && changegrp developers "$name"
done

or,

shopt -s globstar dotglob nullglob

for name in ./**/*' '*/; do
    [[ ! -L ${name%/} ]] && changegrp developers "$name"
done

This uses a simple loop to execute the changegrp command on each directory that have at least one space in its name. It does so by means of the ** globbing pattern (enabled via the globstar shell option in bash) which matches down into subdirectories. The nullglob and dotglob shell options are used to make the shell remove unmatched patterns and to also match hidden names.

The -L test is used here to weed out symbolic links to directories (the -d test would be true for both directories and symbolic links to directories).

In the second variation of the code above, we pick only directories by adding a / at the end of the pattern. This slash needs to be taken off for the -L test, which is what ${name%/} is doing.

It would then be easy to have the string developers be a variable:

shopt -s globstar dotglob nullglob

group=developers

for name in ./**/*' '*; do
    changegrp "$group" "$name"
done

(This code additionally applies changegrp to all names that contain spaces in or under the current directory, as per your other code snippets in the question.)

Kusalananda
  • 333,661