2016-07-26 70 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,它是社區。謝謝。 –