首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在工作目录中带有括号/括号的文件会导致eval错误。

在工作目录中带有括号/括号的文件会导致eval错误。
EN

Unix & Linux用户
提问于 2019-02-17 16:07:18
回答 1查看 4K关注 0票数 5

今天,当我在一个目录中运行一个脚本时,遇到了一个奇怪的错误,其中包含一个带有括号的目录,比如a()

Minimal工作示例

我设法将错误简化为以下最小的工作示例:

/tmpcd中创建一个空目录:

代码语言:javascript
复制
mkdir /tmp/foo
cd /tmp/foo

在其中创建一个名为foo.sh的脚本,其中包含:

代码语言:javascript
复制
foo() {
  somevar=1;
  case somevar in
      aha) echo "something" ;;
      *) echo "other" ;;
  esac;
};

运行以下命令:

代码语言:javascript
复制
eval $(/bin/cat foo.sh)

不应该有任何错误。

创建一个带有括号的文件:

代码语言:javascript
复制
touch "a()"

再次运行命令:

代码语言:javascript
复制
eval $(/bin/cat foo.sh)

我现在得到了错误:

代码语言:javascript
复制
bash: syntax error near unexpected token `(' 

为什么bash甚至关心目录中的文件?为什么括号会导致错误?

System信息:

代码语言:javascript
复制
$ 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 

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详细背景和原始错误:

我的问题来自于使用来自environment-modules包的脚本源D11,如下所述:

代码语言:javascript
复制
$ 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='' ;;'
EN

回答 1

Unix & Linux用户

回答已采纳

发布于 2019-02-17 17:43:13

这在bash中既不奇怪,也不是bug (不过,在/usr/share/modules/init/bash中它确实是一个bug )。您使用的是未引用的命令替换和eval。作为命令替换的结果的字符串,由于没有引号,将经历字分裂和文件名扩展(globbing)。代码中的*)与文件名a()匹配,因此在文件名扩展阶段由该文件名替换。

set -x下运行示例突出说明如下:

代码语言:javascript
复制
$ 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 `('

yash外壳中的相同内容:

代码语言:javascript
复制
$ 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

对于ksh93

代码语言:javascript
复制
$ 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

dash

代码语言:javascript
复制
$ 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 ")")

只有zsh才能处理这个问题,因为它不执行全局操作:

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

正确的处理方法是源foo.sh脚本:

代码语言:javascript
复制
. ./foo.sh

据我所知,没有理由使用eval "$(cat foo.sh)"

这也是一个代码注入漏洞:

代码语言:javascript
复制
$ touch '*) echo "hello" ;; *)'
$ eval $(cat foo.sh)
$ declare -f foo
foo ()
{
    somevar=1;
    case somevar in
        aha)
            echo "something"
        ;;
        *)
            echo "hello"
        ;;
        *)
            echo "other"
        ;;
    esac
}

另一种不需要创建特别命名的文件就很容易中断此命令的方法是将IFS变量设置为一组字符,而不是默认的字符:

代码语言:javascript
复制
$ 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'

这会破坏它,因为在计算eval的参数时,这是因为分词步骤而不是文件全局步骤。使用IFS=';{} ',这些字符中的每个字符将用于将foo.sh中的文本拆分为单词(然后将这些字符从字符串中删除)。

即使是zsh也不会对此免疫:

代码语言:javascript
复制
$ IFS=';{} '
+zsh:2> IFS=';{} '
$ eval $(cat foo.sh)
+zsh:3> cat foo.sh
+zsh:3> eval 'foo()' 相关信息:忘记引用bash/POSIX外壳中的变量的安全性含义什么时候需要双重报价?为什么我的外壳脚本会被空格或其他特殊字符阻塞?\n' 'somevar=1' 相关信息:F126H127C28H229H130C31H232H133C34H235F236\n' case somevar 相关信息:F126H127C28H229H130C31H232H133C34H235F236in\n' 'aha)' echo '"something"' '' 相关信息:F126H127C28H229H130C31H232H133C34H235F236\n' '*)' echo '"other"' '' 相关信息:F126H127C28H229H130C31H232H133C34H235F236\n' esac 相关信息:F126H127C28H229H130C31H232H133C34H235F236\n' '' ''
zsh: parse error near `)'

相关信息:

F126H127

C28

H229H130

C31

H232H133

C34

H235F236

票数 13
EN
页面原文内容由Unix & Linux提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://unix.stackexchange.com/questions/501188

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档