2

I'm trying to write a shell script, and to make it more or less readable, i decided to bring a part of my commands into environment variables:

#!/bin/bash # Variables name_expression="-type d \( -name .folder1 -o -name .wildcardfolder* -o -name .folder2 \)" # Commands find /root/ -maxdepth 1 "$name_expression" -execdir rm -rf {} \; find /home/ -maxdepth 2 "$name_expression" -execdir rm -rf {} \; 

The problem is that if i try to run this shell, many symbols are wrapped with quotes:

bash -x ./my_shell.sh + name_expression='-type d \( -name .android -o -name .AndroidStudio* -o -name .gradle \)' + find /home/ /root/ -maxdepth 2 '-type d \( -name .folder1 -o -name .wildcardfolder* -o -name .folder2 \)' -execdir rm -rf '{}' ';' find: unknown predicate `-type d \( -name .folder1 -o -name .wildcardfolder* -o -name .folder2 \)' 

Is there any way to pass this variable without being modified?

3
  • 1
    See Why does my shell script choke on whitespace or other special characters? This is one of the very few cases where you shouldn't use double quotes when calling the variable. But using the * in there is going to be dangerous. Commented Sep 6, 2017 at 21:50
  • @Wildcard Actually, this is one of the common cases where you should use double quotes (because of the wildcards, among other reasons), but you can't store a list of strings in a string variable. Commented Sep 6, 2017 at 22:49
  • @Gilles, that's what I was trying to convey. See my answer and comments below. Commented Sep 6, 2017 at 22:54

2 Answers 2

3
name_expression=( -type d \( -name .folder1 -o -name .wildcardfolder\* -o -name .folder2 \) ) find /root/ -maxdepth 1 "${name_expression[@]}" -execdir rm -rf {} \; 

Instead of a string parameter which would have to be unquoted in order for the command to see several parts, this uses an array parameter. That way both the splitting and the quoting can be controlled (not completely i.e. per part but in a suitable way for this task).

An alternative which allows complete control would be the use of eval but that would make the rest of the command line more complicated.

5
  • The backslash in .wildcardfolder\* doesn't do what you think it does. The glob can still be expanded (to files with a backslash in the name) and the -name primary won't match the way it was intended. Commented Sep 6, 2017 at 21:54
  • @Wildcard I have not found an explanation for it but bash 4.4.12 does not expand touch 'bar\_' ; testvar="bar\*" ; echo $testvar bar\\*. Does not remove the `\` either. Maybe a shell bug. Commented Sep 6, 2017 at 22:45
  • Interesting. You're right, it doesn't expand. However, it does get treated as an escape by find so that find will only match a literal * character for that position. So this command still won't work. Commented Sep 6, 2017 at 23:00
  • While I personally agree this is the proper way to address the issue, some explanation would be good so people understand what this is doing. Commented Sep 6, 2017 at 23:58
  • (Note: the comments above refer to the earlier revision of this answer, but they contain interesting relevant technical data so shouldn't be deleted IMO.) Commented Sep 7, 2017 at 21:33
2

A modified version that avoids potentially hazardous glob expansions:

cleanupdir() { # args should be dirname, maxdepth find "$1" -maxdepth "$2" -type d \( -name .folder1 -o -name '.wildcardfolder*' -o -name .folder2 \) -execdir rm -rf {} \; } cleanupdir /root 1 cleanupdir /home 2 

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.