File with parentheses/brackets in working directory causes eval error












5















I encountered a strange bug today, when running a script in a directory containing a directory with parentheses in it, such as a().



Minimal working example



I managed to reduce the bug to the following minimal working example:



Create an empty directory in /tmp and cd into it:



mkdir /tmp/foo
cd /tmp/foo


Create a script named foo.sh in it containing:



foo() {
somevar=1;
case somevar in
aha) echo "something" ;;
*) echo "other" ;;
esac;
};


Run the following command:



eval $(/bin/cat foo.sh)


There should not be any error.



Create a file with parentheses:



touch "a()"


Run the command again:



eval $(/bin/cat foo.sh)


I now get the error:



bash: syntax error near unexpected token `(' 


Why does bash even care about what files are in the directory? Why do parentheses cause an error?



System information:



$ bash --version
GNU bash, version 4.4.19(1)-release (x86_64-pc-linux-gnu)
Copyright © 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 18.04.1 LTS
Release: 18.04
Codename: bionic


More detailed background and original error:



My problem came from using a script sourcing /usr/share/modules/init/bash from the environment-modules package, as summarized here:



$ dpkg -l environment-modules 
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name Version Architecture Description
+++-=============================================================-===================================-===================================-================================================================================================================================
ii environment-modules 4.1.1-1 amd64 Modular system for handling environment variables
$ source /usr/share/modules/init/bash
$ touch "a()"
$ source /usr/share/modules/init/bash
bash: eval: line 43: syntax error near unexpected token `('
bash: eval: line 43: ` a() _mlshdbg='' ;;'









share|improve this question

























  • It appears this has already been reported as a bug (and fixed) to the environment-modules package here: github.com/cea-hpc/modules/issues/220 and adding single/double quotes fixes the error. My test script could be simplified to "echo *". But why? Bash and its expansion system still confuses me... I was considering updating my question or answering, but I would really appreciate a clear explanation to what exactly is happening.

    – KIAaze
    Feb 17 at 17:21











  • I'm tempted to mark this as a duplicate of Why does my shell script choke on whitespace or other special characters?

    – ilkkachu
    Feb 17 at 18:01
















5















I encountered a strange bug today, when running a script in a directory containing a directory with parentheses in it, such as a().



Minimal working example



I managed to reduce the bug to the following minimal working example:



Create an empty directory in /tmp and cd into it:



mkdir /tmp/foo
cd /tmp/foo


Create a script named foo.sh in it containing:



foo() {
somevar=1;
case somevar in
aha) echo "something" ;;
*) echo "other" ;;
esac;
};


Run the following command:



eval $(/bin/cat foo.sh)


There should not be any error.



Create a file with parentheses:



touch "a()"


Run the command again:



eval $(/bin/cat foo.sh)


I now get the error:



bash: syntax error near unexpected token `(' 


Why does bash even care about what files are in the directory? Why do parentheses cause an error?



System information:



$ bash --version
GNU bash, version 4.4.19(1)-release (x86_64-pc-linux-gnu)
Copyright © 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 18.04.1 LTS
Release: 18.04
Codename: bionic


More detailed background and original error:



My problem came from using a script sourcing /usr/share/modules/init/bash from the environment-modules package, as summarized here:



$ dpkg -l environment-modules 
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name Version Architecture Description
+++-=============================================================-===================================-===================================-================================================================================================================================
ii environment-modules 4.1.1-1 amd64 Modular system for handling environment variables
$ source /usr/share/modules/init/bash
$ touch "a()"
$ source /usr/share/modules/init/bash
bash: eval: line 43: syntax error near unexpected token `('
bash: eval: line 43: ` a() _mlshdbg='' ;;'









share|improve this question

























  • It appears this has already been reported as a bug (and fixed) to the environment-modules package here: github.com/cea-hpc/modules/issues/220 and adding single/double quotes fixes the error. My test script could be simplified to "echo *". But why? Bash and its expansion system still confuses me... I was considering updating my question or answering, but I would really appreciate a clear explanation to what exactly is happening.

    – KIAaze
    Feb 17 at 17:21











  • I'm tempted to mark this as a duplicate of Why does my shell script choke on whitespace or other special characters?

    – ilkkachu
    Feb 17 at 18:01














5












5








5


3






I encountered a strange bug today, when running a script in a directory containing a directory with parentheses in it, such as a().



Minimal working example



I managed to reduce the bug to the following minimal working example:



Create an empty directory in /tmp and cd into it:



mkdir /tmp/foo
cd /tmp/foo


Create a script named foo.sh in it containing:



foo() {
somevar=1;
case somevar in
aha) echo "something" ;;
*) echo "other" ;;
esac;
};


Run the following command:



eval $(/bin/cat foo.sh)


There should not be any error.



Create a file with parentheses:



touch "a()"


Run the command again:



eval $(/bin/cat foo.sh)


I now get the error:



bash: syntax error near unexpected token `(' 


Why does bash even care about what files are in the directory? Why do parentheses cause an error?



System information:



$ bash --version
GNU bash, version 4.4.19(1)-release (x86_64-pc-linux-gnu)
Copyright © 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 18.04.1 LTS
Release: 18.04
Codename: bionic


More detailed background and original error:



My problem came from using a script sourcing /usr/share/modules/init/bash from the environment-modules package, as summarized here:



$ dpkg -l environment-modules 
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name Version Architecture Description
+++-=============================================================-===================================-===================================-================================================================================================================================
ii environment-modules 4.1.1-1 amd64 Modular system for handling environment variables
$ source /usr/share/modules/init/bash
$ touch "a()"
$ source /usr/share/modules/init/bash
bash: eval: line 43: syntax error near unexpected token `('
bash: eval: line 43: ` a() _mlshdbg='' ;;'









share|improve this question
















I encountered a strange bug today, when running a script in a directory containing a directory with parentheses in it, such as a().



Minimal working example



I managed to reduce the bug to the following minimal working example:



Create an empty directory in /tmp and cd into it:



mkdir /tmp/foo
cd /tmp/foo


Create a script named foo.sh in it containing:



foo() {
somevar=1;
case somevar in
aha) echo "something" ;;
*) echo "other" ;;
esac;
};


Run the following command:



eval $(/bin/cat foo.sh)


There should not be any error.



Create a file with parentheses:



touch "a()"


Run the command again:



eval $(/bin/cat foo.sh)


I now get the error:



bash: syntax error near unexpected token `(' 


Why does bash even care about what files are in the directory? Why do parentheses cause an error?



System information:



$ bash --version
GNU bash, version 4.4.19(1)-release (x86_64-pc-linux-gnu)
Copyright © 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 18.04.1 LTS
Release: 18.04
Codename: bionic


More detailed background and original error:



My problem came from using a script sourcing /usr/share/modules/init/bash from the environment-modules package, as summarized here:



$ dpkg -l environment-modules 
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name Version Architecture Description
+++-=============================================================-===================================-===================================-================================================================================================================================
ii environment-modules 4.1.1-1 amd64 Modular system for handling environment variables
$ source /usr/share/modules/init/bash
$ touch "a()"
$ source /usr/share/modules/init/bash
bash: eval: line 43: syntax error near unexpected token `('
bash: eval: line 43: ` a() _mlshdbg='' ;;'






bash eval module






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Feb 18 at 13:16









Kusalananda

132k17252414




132k17252414










asked Feb 17 at 16:07









KIAazeKIAaze

310213




310213













  • It appears this has already been reported as a bug (and fixed) to the environment-modules package here: github.com/cea-hpc/modules/issues/220 and adding single/double quotes fixes the error. My test script could be simplified to "echo *". But why? Bash and its expansion system still confuses me... I was considering updating my question or answering, but I would really appreciate a clear explanation to what exactly is happening.

    – KIAaze
    Feb 17 at 17:21











  • I'm tempted to mark this as a duplicate of Why does my shell script choke on whitespace or other special characters?

    – ilkkachu
    Feb 17 at 18:01



















  • It appears this has already been reported as a bug (and fixed) to the environment-modules package here: github.com/cea-hpc/modules/issues/220 and adding single/double quotes fixes the error. My test script could be simplified to "echo *". But why? Bash and its expansion system still confuses me... I was considering updating my question or answering, but I would really appreciate a clear explanation to what exactly is happening.

    – KIAaze
    Feb 17 at 17:21











  • I'm tempted to mark this as a duplicate of Why does my shell script choke on whitespace or other special characters?

    – ilkkachu
    Feb 17 at 18:01

















It appears this has already been reported as a bug (and fixed) to the environment-modules package here: github.com/cea-hpc/modules/issues/220 and adding single/double quotes fixes the error. My test script could be simplified to "echo *". But why? Bash and its expansion system still confuses me... I was considering updating my question or answering, but I would really appreciate a clear explanation to what exactly is happening.

– KIAaze
Feb 17 at 17:21





It appears this has already been reported as a bug (and fixed) to the environment-modules package here: github.com/cea-hpc/modules/issues/220 and adding single/double quotes fixes the error. My test script could be simplified to "echo *". But why? Bash and its expansion system still confuses me... I was considering updating my question or answering, but I would really appreciate a clear explanation to what exactly is happening.

– KIAaze
Feb 17 at 17:21













I'm tempted to mark this as a duplicate of Why does my shell script choke on whitespace or other special characters?

– ilkkachu
Feb 17 at 18:01





I'm tempted to mark this as a duplicate of Why does my shell script choke on whitespace or other special characters?

– ilkkachu
Feb 17 at 18:01










1 Answer
1






active

oldest

votes


















13














This is neither strange nor a bug in bash (it does seem to be a bug in /usr/share/modules/init/bash though). You are using an unquoted command substitution together with eval. The string that is the result of the command substitution will, since it is unquoted, undergo word splitting and filename expansion (globbing). The *) in the code matches the filename a(), so it is replace by this filename in the filename expansion stage.



Running your example under set -x highlights this:



$ eval $(cat foo.sh)
++ cat foo.sh
+ eval 'foo()' '{' 'somevar=1;' case somevar in 'aha)' echo '"something"' ';;' 'a()' echo '"other"' ';;' 'esac;' '};'
bash: syntax error near unexpected token `('


The same thing in the yash shell:



$ eval $(cat foo.sh)
+ cat foo.sh
+ eval 'foo()' '{' 'somevar=1;' case somevar in 'aha)' echo '"something"' ';;' 'a()' echo '"other"' ';;' 'esac;' '};'
eval:1: syntax error: `)' is missing
eval:1: syntax error: `esac' is missing
eval:1: syntax error: `}' is missing


And with ksh93:



$ eval $(cat foo.sh)
+ cat foo.sh
+ eval 'foo()' '{' somevar='1;' case somevar in 'aha)' echo '"something"' ';;' 'a()' echo '"other"' ';;' 'esac;' '};'
ksh93: eval: syntax error: `(' unexpected


And dash:



$ eval $(cat foo.sh)
+ cat foo.sh
+ eval foo() { somevar=1; case somevar in aha) echo "something" ;; a() echo "other" ;; esac; };
dash: 1: eval: Syntax error: "(" unexpected (expecting ")")


Only the zsh would handle this as it does not perform the globbing:



$ eval $(cat foo.sh)
+zsh:2> cat foo.sh
+zsh:2> eval 'foo()' '{' 'somevar=1;' case somevar in 'aha)' echo '"something"' ';;' '*)' echo '"other"' ';;' 'esac;' '};'


The correct way to handle this would be to source the foo.sh script:



. ./foo.sh


There is really no reason to use eval "$(cat foo.sh)" as far as I can see.



This is also a code injection vulnerability:



$ touch '*) echo "hello" ;; *)'
$ eval $(cat foo.sh)
$ declare -f foo
foo ()
{
somevar=1;
case somevar in
aha)
echo "something"
;;
*)
echo "hello"
;;
*)
echo "other"
;;
esac
}


Another way of breaking this command easily without creating a specially named file, is to set the IFS variable to a set of characters other than the default:



$ IFS=';{} '
+ IFS=';{} '
$ eval $(cat foo.sh)
++ cat foo.sh
+ eval 'foo()' '
' somevar=1 '
' case somevar 'in
' 'aha)' echo '"something"' '' '
' '*)' echo '"other"' '' '
' esac '
' ''
bash: syntax error near unexpected token `somevar=1'


This breaks it because of the word-splitting step rather than the file globbing step in the evaluation of the arguments to eval. With IFS=';{} ', each of those characters would be used to split the text in foo.sh up into words (and those characters would then be removed from the string).



Not even zsh would be immune to this:



$ IFS=';{} '
+zsh:2> IFS=';{} '
$ eval $(cat foo.sh)
+zsh:3> cat foo.sh
+zsh:3> eval 'foo()' $'n' 'somevar=1' $'n' case somevar $'inn' 'aha)' echo '"something"' '' $'n' '*)' echo '"other"' '' $'n' esac $'n' '' ''
zsh: parse error near `)'


Related:




  • Security implications of forgetting to quote a variable in bash/POSIX shells

  • When is double-quoting necessary?

  • Why does my shell script choke on whitespace or other special characters?






share|improve this answer





















  • 1





    Thanks. I learned a bit more about bash again. :) (In particular, "set -f" can fix the error too by disable filename expansion.) I also finally upgraded to Ubuntu 18.10, which fixed the environment-modules error.

    – KIAaze
    Feb 18 at 22:06











Your Answer








StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "106"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f501188%2ffile-with-parentheses-brackets-in-working-directory-causes-eval-error%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









13














This is neither strange nor a bug in bash (it does seem to be a bug in /usr/share/modules/init/bash though). You are using an unquoted command substitution together with eval. The string that is the result of the command substitution will, since it is unquoted, undergo word splitting and filename expansion (globbing). The *) in the code matches the filename a(), so it is replace by this filename in the filename expansion stage.



Running your example under set -x highlights this:



$ eval $(cat foo.sh)
++ cat foo.sh
+ eval 'foo()' '{' 'somevar=1;' case somevar in 'aha)' echo '"something"' ';;' 'a()' echo '"other"' ';;' 'esac;' '};'
bash: syntax error near unexpected token `('


The same thing in the yash shell:



$ eval $(cat foo.sh)
+ cat foo.sh
+ eval 'foo()' '{' 'somevar=1;' case somevar in 'aha)' echo '"something"' ';;' 'a()' echo '"other"' ';;' 'esac;' '};'
eval:1: syntax error: `)' is missing
eval:1: syntax error: `esac' is missing
eval:1: syntax error: `}' is missing


And with ksh93:



$ eval $(cat foo.sh)
+ cat foo.sh
+ eval 'foo()' '{' somevar='1;' case somevar in 'aha)' echo '"something"' ';;' 'a()' echo '"other"' ';;' 'esac;' '};'
ksh93: eval: syntax error: `(' unexpected


And dash:



$ eval $(cat foo.sh)
+ cat foo.sh
+ eval foo() { somevar=1; case somevar in aha) echo "something" ;; a() echo "other" ;; esac; };
dash: 1: eval: Syntax error: "(" unexpected (expecting ")")


Only the zsh would handle this as it does not perform the globbing:



$ eval $(cat foo.sh)
+zsh:2> cat foo.sh
+zsh:2> eval 'foo()' '{' 'somevar=1;' case somevar in 'aha)' echo '"something"' ';;' '*)' echo '"other"' ';;' 'esac;' '};'


The correct way to handle this would be to source the foo.sh script:



. ./foo.sh


There is really no reason to use eval "$(cat foo.sh)" as far as I can see.



This is also a code injection vulnerability:



$ touch '*) echo "hello" ;; *)'
$ eval $(cat foo.sh)
$ declare -f foo
foo ()
{
somevar=1;
case somevar in
aha)
echo "something"
;;
*)
echo "hello"
;;
*)
echo "other"
;;
esac
}


Another way of breaking this command easily without creating a specially named file, is to set the IFS variable to a set of characters other than the default:



$ IFS=';{} '
+ IFS=';{} '
$ eval $(cat foo.sh)
++ cat foo.sh
+ eval 'foo()' '
' somevar=1 '
' case somevar 'in
' 'aha)' echo '"something"' '' '
' '*)' echo '"other"' '' '
' esac '
' ''
bash: syntax error near unexpected token `somevar=1'


This breaks it because of the word-splitting step rather than the file globbing step in the evaluation of the arguments to eval. With IFS=';{} ', each of those characters would be used to split the text in foo.sh up into words (and those characters would then be removed from the string).



Not even zsh would be immune to this:



$ IFS=';{} '
+zsh:2> IFS=';{} '
$ eval $(cat foo.sh)
+zsh:3> cat foo.sh
+zsh:3> eval 'foo()' $'n' 'somevar=1' $'n' case somevar $'inn' 'aha)' echo '"something"' '' $'n' '*)' echo '"other"' '' $'n' esac $'n' '' ''
zsh: parse error near `)'


Related:




  • Security implications of forgetting to quote a variable in bash/POSIX shells

  • When is double-quoting necessary?

  • Why does my shell script choke on whitespace or other special characters?






share|improve this answer





















  • 1





    Thanks. I learned a bit more about bash again. :) (In particular, "set -f" can fix the error too by disable filename expansion.) I also finally upgraded to Ubuntu 18.10, which fixed the environment-modules error.

    – KIAaze
    Feb 18 at 22:06
















13














This is neither strange nor a bug in bash (it does seem to be a bug in /usr/share/modules/init/bash though). You are using an unquoted command substitution together with eval. The string that is the result of the command substitution will, since it is unquoted, undergo word splitting and filename expansion (globbing). The *) in the code matches the filename a(), so it is replace by this filename in the filename expansion stage.



Running your example under set -x highlights this:



$ eval $(cat foo.sh)
++ cat foo.sh
+ eval 'foo()' '{' 'somevar=1;' case somevar in 'aha)' echo '"something"' ';;' 'a()' echo '"other"' ';;' 'esac;' '};'
bash: syntax error near unexpected token `('


The same thing in the yash shell:



$ eval $(cat foo.sh)
+ cat foo.sh
+ eval 'foo()' '{' 'somevar=1;' case somevar in 'aha)' echo '"something"' ';;' 'a()' echo '"other"' ';;' 'esac;' '};'
eval:1: syntax error: `)' is missing
eval:1: syntax error: `esac' is missing
eval:1: syntax error: `}' is missing


And with ksh93:



$ eval $(cat foo.sh)
+ cat foo.sh
+ eval 'foo()' '{' somevar='1;' case somevar in 'aha)' echo '"something"' ';;' 'a()' echo '"other"' ';;' 'esac;' '};'
ksh93: eval: syntax error: `(' unexpected


And dash:



$ eval $(cat foo.sh)
+ cat foo.sh
+ eval foo() { somevar=1; case somevar in aha) echo "something" ;; a() echo "other" ;; esac; };
dash: 1: eval: Syntax error: "(" unexpected (expecting ")")


Only the zsh would handle this as it does not perform the globbing:



$ eval $(cat foo.sh)
+zsh:2> cat foo.sh
+zsh:2> eval 'foo()' '{' 'somevar=1;' case somevar in 'aha)' echo '"something"' ';;' '*)' echo '"other"' ';;' 'esac;' '};'


The correct way to handle this would be to source the foo.sh script:



. ./foo.sh


There is really no reason to use eval "$(cat foo.sh)" as far as I can see.



This is also a code injection vulnerability:



$ touch '*) echo "hello" ;; *)'
$ eval $(cat foo.sh)
$ declare -f foo
foo ()
{
somevar=1;
case somevar in
aha)
echo "something"
;;
*)
echo "hello"
;;
*)
echo "other"
;;
esac
}


Another way of breaking this command easily without creating a specially named file, is to set the IFS variable to a set of characters other than the default:



$ IFS=';{} '
+ IFS=';{} '
$ eval $(cat foo.sh)
++ cat foo.sh
+ eval 'foo()' '
' somevar=1 '
' case somevar 'in
' 'aha)' echo '"something"' '' '
' '*)' echo '"other"' '' '
' esac '
' ''
bash: syntax error near unexpected token `somevar=1'


This breaks it because of the word-splitting step rather than the file globbing step in the evaluation of the arguments to eval. With IFS=';{} ', each of those characters would be used to split the text in foo.sh up into words (and those characters would then be removed from the string).



Not even zsh would be immune to this:



$ IFS=';{} '
+zsh:2> IFS=';{} '
$ eval $(cat foo.sh)
+zsh:3> cat foo.sh
+zsh:3> eval 'foo()' $'n' 'somevar=1' $'n' case somevar $'inn' 'aha)' echo '"something"' '' $'n' '*)' echo '"other"' '' $'n' esac $'n' '' ''
zsh: parse error near `)'


Related:




  • Security implications of forgetting to quote a variable in bash/POSIX shells

  • When is double-quoting necessary?

  • Why does my shell script choke on whitespace or other special characters?






share|improve this answer





















  • 1





    Thanks. I learned a bit more about bash again. :) (In particular, "set -f" can fix the error too by disable filename expansion.) I also finally upgraded to Ubuntu 18.10, which fixed the environment-modules error.

    – KIAaze
    Feb 18 at 22:06














13












13








13







This is neither strange nor a bug in bash (it does seem to be a bug in /usr/share/modules/init/bash though). You are using an unquoted command substitution together with eval. The string that is the result of the command substitution will, since it is unquoted, undergo word splitting and filename expansion (globbing). The *) in the code matches the filename a(), so it is replace by this filename in the filename expansion stage.



Running your example under set -x highlights this:



$ eval $(cat foo.sh)
++ cat foo.sh
+ eval 'foo()' '{' 'somevar=1;' case somevar in 'aha)' echo '"something"' ';;' 'a()' echo '"other"' ';;' 'esac;' '};'
bash: syntax error near unexpected token `('


The same thing in the yash shell:



$ eval $(cat foo.sh)
+ cat foo.sh
+ eval 'foo()' '{' 'somevar=1;' case somevar in 'aha)' echo '"something"' ';;' 'a()' echo '"other"' ';;' 'esac;' '};'
eval:1: syntax error: `)' is missing
eval:1: syntax error: `esac' is missing
eval:1: syntax error: `}' is missing


And with ksh93:



$ eval $(cat foo.sh)
+ cat foo.sh
+ eval 'foo()' '{' somevar='1;' case somevar in 'aha)' echo '"something"' ';;' 'a()' echo '"other"' ';;' 'esac;' '};'
ksh93: eval: syntax error: `(' unexpected


And dash:



$ eval $(cat foo.sh)
+ cat foo.sh
+ eval foo() { somevar=1; case somevar in aha) echo "something" ;; a() echo "other" ;; esac; };
dash: 1: eval: Syntax error: "(" unexpected (expecting ")")


Only the zsh would handle this as it does not perform the globbing:



$ eval $(cat foo.sh)
+zsh:2> cat foo.sh
+zsh:2> eval 'foo()' '{' 'somevar=1;' case somevar in 'aha)' echo '"something"' ';;' '*)' echo '"other"' ';;' 'esac;' '};'


The correct way to handle this would be to source the foo.sh script:



. ./foo.sh


There is really no reason to use eval "$(cat foo.sh)" as far as I can see.



This is also a code injection vulnerability:



$ touch '*) echo "hello" ;; *)'
$ eval $(cat foo.sh)
$ declare -f foo
foo ()
{
somevar=1;
case somevar in
aha)
echo "something"
;;
*)
echo "hello"
;;
*)
echo "other"
;;
esac
}


Another way of breaking this command easily without creating a specially named file, is to set the IFS variable to a set of characters other than the default:



$ IFS=';{} '
+ IFS=';{} '
$ eval $(cat foo.sh)
++ cat foo.sh
+ eval 'foo()' '
' somevar=1 '
' case somevar 'in
' 'aha)' echo '"something"' '' '
' '*)' echo '"other"' '' '
' esac '
' ''
bash: syntax error near unexpected token `somevar=1'


This breaks it because of the word-splitting step rather than the file globbing step in the evaluation of the arguments to eval. With IFS=';{} ', each of those characters would be used to split the text in foo.sh up into words (and those characters would then be removed from the string).



Not even zsh would be immune to this:



$ IFS=';{} '
+zsh:2> IFS=';{} '
$ eval $(cat foo.sh)
+zsh:3> cat foo.sh
+zsh:3> eval 'foo()' $'n' 'somevar=1' $'n' case somevar $'inn' 'aha)' echo '"something"' '' $'n' '*)' echo '"other"' '' $'n' esac $'n' '' ''
zsh: parse error near `)'


Related:




  • Security implications of forgetting to quote a variable in bash/POSIX shells

  • When is double-quoting necessary?

  • Why does my shell script choke on whitespace or other special characters?






share|improve this answer















This is neither strange nor a bug in bash (it does seem to be a bug in /usr/share/modules/init/bash though). You are using an unquoted command substitution together with eval. The string that is the result of the command substitution will, since it is unquoted, undergo word splitting and filename expansion (globbing). The *) in the code matches the filename a(), so it is replace by this filename in the filename expansion stage.



Running your example under set -x highlights this:



$ eval $(cat foo.sh)
++ cat foo.sh
+ eval 'foo()' '{' 'somevar=1;' case somevar in 'aha)' echo '"something"' ';;' 'a()' echo '"other"' ';;' 'esac;' '};'
bash: syntax error near unexpected token `('


The same thing in the yash shell:



$ eval $(cat foo.sh)
+ cat foo.sh
+ eval 'foo()' '{' 'somevar=1;' case somevar in 'aha)' echo '"something"' ';;' 'a()' echo '"other"' ';;' 'esac;' '};'
eval:1: syntax error: `)' is missing
eval:1: syntax error: `esac' is missing
eval:1: syntax error: `}' is missing


And with ksh93:



$ eval $(cat foo.sh)
+ cat foo.sh
+ eval 'foo()' '{' somevar='1;' case somevar in 'aha)' echo '"something"' ';;' 'a()' echo '"other"' ';;' 'esac;' '};'
ksh93: eval: syntax error: `(' unexpected


And dash:



$ eval $(cat foo.sh)
+ cat foo.sh
+ eval foo() { somevar=1; case somevar in aha) echo "something" ;; a() echo "other" ;; esac; };
dash: 1: eval: Syntax error: "(" unexpected (expecting ")")


Only the zsh would handle this as it does not perform the globbing:



$ eval $(cat foo.sh)
+zsh:2> cat foo.sh
+zsh:2> eval 'foo()' '{' 'somevar=1;' case somevar in 'aha)' echo '"something"' ';;' '*)' echo '"other"' ';;' 'esac;' '};'


The correct way to handle this would be to source the foo.sh script:



. ./foo.sh


There is really no reason to use eval "$(cat foo.sh)" as far as I can see.



This is also a code injection vulnerability:



$ touch '*) echo "hello" ;; *)'
$ eval $(cat foo.sh)
$ declare -f foo
foo ()
{
somevar=1;
case somevar in
aha)
echo "something"
;;
*)
echo "hello"
;;
*)
echo "other"
;;
esac
}


Another way of breaking this command easily without creating a specially named file, is to set the IFS variable to a set of characters other than the default:



$ IFS=';{} '
+ IFS=';{} '
$ eval $(cat foo.sh)
++ cat foo.sh
+ eval 'foo()' '
' somevar=1 '
' case somevar 'in
' 'aha)' echo '"something"' '' '
' '*)' echo '"other"' '' '
' esac '
' ''
bash: syntax error near unexpected token `somevar=1'


This breaks it because of the word-splitting step rather than the file globbing step in the evaluation of the arguments to eval. With IFS=';{} ', each of those characters would be used to split the text in foo.sh up into words (and those characters would then be removed from the string).



Not even zsh would be immune to this:



$ IFS=';{} '
+zsh:2> IFS=';{} '
$ eval $(cat foo.sh)
+zsh:3> cat foo.sh
+zsh:3> eval 'foo()' $'n' 'somevar=1' $'n' case somevar $'inn' 'aha)' echo '"something"' '' $'n' '*)' echo '"other"' '' $'n' esac $'n' '' ''
zsh: parse error near `)'


Related:




  • Security implications of forgetting to quote a variable in bash/POSIX shells

  • When is double-quoting necessary?

  • Why does my shell script choke on whitespace or other special characters?







share|improve this answer














share|improve this answer



share|improve this answer








edited Feb 18 at 13:15

























answered Feb 17 at 17:43









KusalanandaKusalananda

132k17252414




132k17252414








  • 1





    Thanks. I learned a bit more about bash again. :) (In particular, "set -f" can fix the error too by disable filename expansion.) I also finally upgraded to Ubuntu 18.10, which fixed the environment-modules error.

    – KIAaze
    Feb 18 at 22:06














  • 1





    Thanks. I learned a bit more about bash again. :) (In particular, "set -f" can fix the error too by disable filename expansion.) I also finally upgraded to Ubuntu 18.10, which fixed the environment-modules error.

    – KIAaze
    Feb 18 at 22:06








1




1





Thanks. I learned a bit more about bash again. :) (In particular, "set -f" can fix the error too by disable filename expansion.) I also finally upgraded to Ubuntu 18.10, which fixed the environment-modules error.

– KIAaze
Feb 18 at 22:06





Thanks. I learned a bit more about bash again. :) (In particular, "set -f" can fix the error too by disable filename expansion.) I also finally upgraded to Ubuntu 18.10, which fixed the environment-modules error.

– KIAaze
Feb 18 at 22:06


















draft saved

draft discarded




















































Thanks for contributing an answer to Unix & Linux Stack Exchange!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f501188%2ffile-with-parentheses-brackets-in-working-directory-causes-eval-error%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Biblatex bibliography style without URLs when DOI exists (in Overleaf with Zotero bibliography)

ComboBox Display Member on multiple fields

Is it possible to collect Nectar points via Trainline?