0

I have a script calling this

find "/mnt/Data/Shared/$1" -type d -exec bash -c 'fixperm "'${1}'" "fd" "$0"' {} \;

$1 is a directory, when the name contains no spaces it works, when there is a space its fails an returns errors. Testing with "00_Office Test"

Test" "fd" "$0": -c: line 0: unexpected EOF while looking for matching `"'
Test" "fd" "$0": -c: line 1: syntax error: unexpected end of file

I thought it may be because the path was missing the \ before the space but that does not fix the issue. I'm sure I'm missing something trivial here.

1

2 Answers 2

3

That's because the ${1} appears outside of single quotes, i.e. it gets expanded and word-split by the shell before find even sees it. The syntax highlighting here on StackExchange shows it clearly. Use double quotes to prevent the word splitting.

Also, by calling bash -c, you need to handle quoting yourself, but it can break if the file name contains a double quote. Don't use it and pass the parameters directly:

find "/mnt/Data/Shared/$1" -type d -exec fixperm "$1" fd {} \;
4
  • I think the $0 would be the parameter that gets passed to bash -c 'cmd' -- -exec fixperm "$1" fd {} \; might be better. Commented Jul 17, 2019 at 15:57
  • @glennjackman: You're right, fixed. I felt it was weird. But not having fixperm and having no idea what the expected behaviour was, I couldn't test it.
    – choroba
    Commented Jul 17, 2019 at 16:01
  • fixperm is a sub routine being exported and this method may be workable but the other answer solved with minimal change and this did not work because bash did not know about fixperm
    – SBTech
    Commented Jul 17, 2019 at 19:22
  • 1
    @SBTech, the probability is that fixperm is just a chmod command of some sort, wrapped in a Bash function. If so, you might as well just put it as -exec chmod ... rather than using a function.
    – Wildcard
    Commented Jul 18, 2019 at 20:52
1

That's because you are using an unquoted ${1}.

Quoting

Solving quoting issues could get quite complex.

Replacing '${1}' with '"${1}"' might seem to help.

Compare:

$ set -- "ab cd"; bash -c 'printf "<%s> " '${1}' "fd" "$0"'
<ab>

with:

$ set -- "ab cd"; bash -c 'printf "<%s> " '"${1}"' "fd" "$0"'
<ab> <cd> <fd> <bash>

However, shell "quote removal" is still applied to the variable value.
As a workaround you could use '"${1@Q}"'

$ set -- 'a"b c"d'; bash -c 'printf "<%s> " '"${1}"' "fd" "$0"'; echo
<ab cd> <fd> <bash>               # quotes got lost.

$ set -- 'a"bc"d'; bash -c 'printf "<%s> " '"${1@Q}"' "fd" "$0"'; echo
<a"b c"d> <fd> <bash>             # correct quotes.

But, still, that doesn't work for the two loops of shell exposure that your command has (first to the find command, then to the bash -c command):

$ mkdir 'a"bc"d' 'a"b c"d' 'a"bcd'

$ set -- 'a"bc"d'; find "./$1" -type d -exec bash -c 'printf "<%s> " fixperm "'"${1}"'" "fd" "$0"' {} >
<fixperm> <abcd> <fd> <./a"b c"d>

$ set -- 'a"b c"d'; find "./$1" -type d -exec bash -c 'printf "<%s> " fixperm "'"${1}"'" "fd" "$0"' {} >
<fixperm> <ab> <cd> <fd> <./a"b c"d>

$ set -- 'a"bcd'; find "./$1" -type d -exec bash -c 'printf "<%s> " fixperm "'"${1}"'" "fd" "$0"' {} \; 
./a"bcd: -c: line 0: unexpected EOF while looking for matching `"'
./a"bcd: -c: line 1: syntax error: unexpected end of file

Correct

However, what really happens is that there seems to be a confusion between the $1 that is a parameter of the script you call and what $1 means to the shell that is being called with bash -c

The line:

find "/mnt/Data/Shared/$1" -type d -exec bash -c '
     fixperm "'"${1}"'" "fd" "$0"' {} \;

Should read:

find "/mnt/Data/Shared/$1" -type d -exec bash -c '
     fixperm "$1" "fd" "$2"' bash-shell "$1" {} \;

Which makes the quoting direct and a lot more robust.

Simple

If there is no loop or other complex function to run inside the bash -c script, almost all quoting could be removed and write:

dir="/mnt/Data/Shared"

find "$dir/$1" -type d -exec fixperm "$1" fd {} \;
5
  • its ugly but it works! find "/mnt/Data/Shared/$1" -type d -exec bash -c 'fixperm "'"$1"'" "fd" "$0"' {} \;
    – SBTech
    Commented Jul 17, 2019 at 19:19
  • Does is work for filenames containing double quotes?
    – choroba
    Commented Jul 17, 2019 at 19:34
  • @choroba As long as the variable ($1 in this case) contains the quotes I can not find a way to make it fail. Care to show an example where it fails?
    – user232326
    Commented Jul 17, 2019 at 21:13
  • In the set example, use set -- 'a"b"c', the double quotes will be lost; using 'a"b' makes it fail.
    – choroba
    Commented Jul 17, 2019 at 23:48
  • @choroba Thanks for your comments. Answer corrected. I believe that now it is correct.
    – user232326
    Commented Jul 18, 2019 at 22:21

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .