2016-07-26 8 views
1

私はbashのかなり不思議なバグに出くわしました。これはシェル拡張ルールと関係があると思われます。bashが "ls /"の出力を出力に挿入しているのはなぜですか?

ここには物語があります。職場では、社内リソースを調整するための大規模な社内Webサイトを文書化する必要があります。残念ながら、このコードは元の目的を上回り、企業の取り組みを調整するための主要リソースに「進化」しているので、かなり醜いです。

ほとんどのコードは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 
} 

がさらに紛らわしい、私は1つの特定のファイルから一つの特定の機能のために発生し、これを得ています!今では関数が非常に巨大なので(500行以上、コードが醜いと言っているのですが)、私の人生で何が起こっているのか把握することができませんでした。この動作を生成するためのより単純なアドホック関数です。また、会社のポリシーにより、実際のコードを共有することができなくなります。

しかし、ここに私のコードは次のとおりです。

#!/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 

はい、私はPHPのコードを操作するためにはbashを使用してはならないことを知っているが、私は基本的に2つの質問があります。

1)どうしてれますこれをやっているbash?

2)どうすれば修正できますか?

+0

あなたは '[[-z" $ file_name "]] ||で何を達成しようとしていますか? ["$ file_name" = " - "];その後、 file_name = "/ dev/stdin"; fi'? – sjsam

+0

@sjsadmファイル名が指定されていないか、 ' - 'に等しい場合、stdinから読み込みます。 「猫」のようなものも、配管を容易にします。 –

答えて

6

$tokensのトークンの1つは、*(または複数のファイルに一致する可能性のあるグロブパターン)です。トークンリストがシェルメタキャラクタを含まないように手配できない場合、展開を避けるためにいくつかのフープを飛び越す必要があります。考えられる手法の1つは、read -raを使用してトークンを配列に読み込む方法です。これにより、トークンを簡単に引用できます。

+1

これは私が本当にスタックオーバーフローとそれがコミュニティに感謝するこれらの瞬間です。ありがとう。 –

関連する問題