2016-07-26 5 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 + lines, 나는 코드가 추악하다는 것을 말할 때 그것을 의미합니다!), 나는이 일의 원인을 찾아 내거나, 생각해 낼 수 없었습니다. 이 동작을 생성하는 더 단순한 ad-hoc 함수. 또한 회사 정책에 따라 실제 코드를 공유하지 못하게됩니다. 왜)

1 : 예, 제가 PHP 코드를 조작하는 떠들썩한 파티를 사용하지 않는 것을 알고 있지만, 나는 기본적으로 두 가지 질문이

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

2) 어떻게 해결할 수 있습니까?

+0

'[[-z "$ file_name"]] ||로 무엇을하려합니까? [ "$ file_name"= "-"]; 그때; file_name = "/ dev/stdin"; fi'? – sjsam

+0

@sjsadm 파일 이름이 지정되지 않았거나 '-'와 같으면 stdin에서 읽습니다. '고양이'와 같은 종류의 것도 배관을 더 쉽게 만듭니다. –

답변

6

$tokens의 토큰 중 하나는 * (또는 여러 파일과 일치 할 수있는 glob 패턴)입니다. 셸 메타 문자가 포함되지 않도록 토큰 목록을 정렬 할 수없는 경우 확장을 피하기 위해 일부 농구를 뛰어 넘을 필요가 있습니다. 가능한 한 기술은 read -ra을 사용하여 토큰을 배열로 읽는 것입니다. 이렇게하면 토큰을 쉽게 인용 할 수 있습니다.

+1

이러한 순간에 저는 Stack Overflow와 커뮤니티를 정말 고맙게 생각합니다. 감사. –