2016-07-26 74 views
1

我遇到在bash一个相当神秘的错误,我怀疑有壳扩规的事情。为什么bash在输出中插入“ls /”的输出?

这里的故事:在工作中,我一直在负责记录一个庞大的内部网站,协调公司资源。不幸的是,这些代码相当丑陋,因为它已经超出了原来的目的,并且“演变”为协调公司工作的主要资源。

大部分的代码是PHP。我写了几个帮手脚本来帮助我编写文档;例如,一个脚本提取所有php函数中使用的全局php变量。

在所有这些脚本的中心位于“extract_function.sh”脚本。基本上,给定一个PHP函数名称和一个PHP源文件,它提取并输出该PHP函数。

现在,这里的问题:不知何故,作为脚本提取功能,它基本上是随机插入的输出中的ls /输出。

例如:

$ ./extract_function my_function my_php_file.php 
function my_function { 
    // php code 
/etc 
/bin 
/proc 
... 
    // more php code 
} 

更容易混淆的,我只得到这从一个特定的文件中某一特定功能发生!现在,由于该函数非常庞大(超过500行,我说的是当我说代码很丑时!),但我一直无法弄清楚是什么原因造成的,或者想出了什么一个更简单的ad-hoc功能来产生这种行为。此外,公司政策阻止我分享实际的代码。

然而,这里是我的代码:

#!/usr/bin/env bash 
program_name=$(basename $0); 
function_name=$1; 
file_name=$2; 

if [[ -z "$function_name" ]]; then 
    (>&2 echo "Usage: $program_name function_name [file]") 
    exit 1 
fi 

if [[ -z "$file_name" ]] || [ "$file_name" = "-" ]; then 
    file_name="/dev/stdin"; 
fi 

php_lexer_file=$(mktemp) 
trap "rm -f $php_lexer_file" EXIT 
read -r -d '' php_lexer_text << 'EOF' 
<?php 
    $file = file_get_contents("php://stdin"); 
    $tokens = token_get_all($file); 
    foreach ($tokens as $token) 
     if ($token === '{') 
      echo PHP_EOL, "PHP_BRACKET_OPEN", PHP_EOL; 
     else if ($token == '}') 
      echo PHP_EOL, "PHP_BRACKET_CLOSE", PHP_EOL; 
     else if (is_array($token)) 
      echo $token[1]; 
     else 
      echo $token; 
?> 
EOF 
echo "$php_lexer_text" > $php_lexer_file; 

# Get all output from beginning of function declaration 
extracted_function_start=$(sed -n -e "/function $function_name(/,$ p" < $file_name); 

# Prepend <?php so that php will parse the file as php 
extracted_function_file=$(mktemp) 
trap "rm -f $extracted_function_file" EXIT 
echo '<?php' > $extracted_function_file; 
echo "$extracted_function_start" >> $extracted_function_file; 
tokens=$(php $php_lexer_file < $extracted_function_file); 
# I've checked, and at this point $tokens does not contain "/bin", "/lib", etc... 

IFS=$'\n'; 
open_count=0; 
close_count=0; 
for token in $tokens; do # But here the output of "ls /" magically appears in $tokens! 
    if [ $token = "PHP_BRACKET_OPEN" ]; then 
     open_count=$((open_count+1)) 
     token='{'; 
    elif [ $token == "PHP_BRACKET_CLOSE" ] ; then 
     close_count=$((close_count+1)) 
     token='}'; 
    fi 

    echo $token; 
    if [ $open_count -ne 0 ] && [ $open_count -eq $close_count ]; then 
     break; 
    fi 
done 

是的,我知道我不应该使用bash操纵PHP代码,但我基本上有两个问题:

1)为什么bash这样做?

2)而且,我该如何解决?

+0

你在用'if [[-z“$ file_name”]] ||来完成什么? [“$ file_name”=“ - ”];然后; FILE_NAME = “的/ dev /标准输入”; fi'? – sjsam

+0

@sjsadm如果文件名未指定或等于' - ',则从标准输入读取。有点像'猫',也使管道更容易。 –

回答

6

$tokens中的一个令牌是*(或可匹配多个文件的glob模式)。如果您无法安排令牌列表不包含shell元字符,则需要跳过一些环节以避免扩展。一种可能的技术是使用read -ra将令牌读入数组中,这将使它更容易引用它们。

+1

在这些时刻,我真的很感激Stack Overflow,它是社区。谢谢。 –