2013-08-18 5 views
0

많은 파일을 수정하는 아주 간단한 bash 스크립트를 작성하려고합니다. 명령이 성공적으로 완료되었는지 확인하기 위해 각 명령의 결과를 로그에 출력하고 있습니다 . 스크립트에 변수가있는 CAT을 전달할 수 없다는 것을 제외하고는 모든 것이 작동하는 것 같습니다. 계속 cat: >>: No such file or directory 오류가 발생합니다.함수에 인수로 CAT 명령을 전달하십시오.

#! /bin/bash 

file1="./file1" 
file2="./file2" 

check() { 
    if ($1 > /dev/null) then 
    echo "  $1 : completed" | tee -a log 
    return 0; 
    else 
    echo "ERR> $1 : command failed" | tee -a log 
    return 1; 
    fi 
} 

check "cp $file1 $file1.bak"   # this works fine 
check "sed -i s/text/newtext/g $file1" # this works, too 
check "cat $file1 >> $file2"   # this does not work 

나는 여러 가지 조합을 시도했다. 나는 그것이 작동시킬 수있는 유일한 방법은 다음 사용하는 것입니다 :

check $(cat $file1 >> $file2) 

그러나,이 check에 명령 자체를 통과하지 않는 경우에만 반환 값을, 그래서 기능 check에서 $1/dev/null 아닌 명령을 수행 공연, 내가 원하는 특정 행동하지 않습니다. 나는이 솔루션은 오히려 간단하다 확신

 cp ./file1 ./file1.bak : completed 
    sed -i s/text/newtext/g ./file1 : completed 
ERR> cat ./file1 >> ./file2 : command failed 

하지만, 몇 시간 동안 저를 회피하고 Google 검색 아무리 어떤 도움을 굴복 없다 : 같은

그냥 완성도를 들어, log 파일이 보인다 . 모양을 가져 주셔서 감사합니다.

답변

0

cat 명령의 I/O 리디렉션이 I/O 리디렉션이 아니라 cat 명령의 간단한 인수로 해석되는 것이 문제입니다. 슬픔을 일으키는 I/O 리디렉션만큼이나 cat이 아닙니다. 파이프 라인을 사용하면 문제가 발생할 수도 있습니다. 이 문제를 해결하는 데 사용할 수

옵션은 다음과 같습니다 : 하나 $file1 또는 $file2 쉘 특수 문자가 포함 된

check "cp $file1 $file2" # Use copy instead of cat and I/O redirection; clobbers file2 

check "eval cat $file1 >> $file2" # Use eval to handle I/O redirection, piping, etc 

경우, eval 옵션은 위험하다.

cp 명령은 I/O 리디렉션 없이도 작동하는 것을 대체합니다. 당신은 작업 처리하기 (현미경) 쉘 스크립트를 사용할 수 - 스크립트가 쉘 스크립트를 실행하고, 쉘 스크립트는 재 처리 :이 중 하나를 인수하는 경우 기본 오류 메시지를 생성

#!/bin/sh 
exec cat ${1:?} >> ${2:?} 

을 1 또는 2 누락되었습니다 (그러나 추가 인수에 반대하지 않습니다).

+0

'$ file1'과'$ file2'는 경로와 파일 이름을 포함합니다. 예를 들어'eval cat ./mypath/rm./mypath/file'을 사용하면'rm./mypath/file'을 평가할 수 있습니까? – cdm

+0

파일 이름의 주요 문제점 문자는 공백, 달러 기호, 백틱 (back-tick)과 같은 것입니다. 쉘에 특별한 의미가있는 것들. 'file1 = "./ mypath/rm"'및'file2 = "./ mypath/file"'이면, 근본적으로 문제를 일으킬 방법이 없습니다. 이름을 관리하는 경우 (사용자 입력이 없음), 아마 괜찮을 것입니다. 사용자 입력을 처리해야한다면 파일 이름으로'file1 = '$ (rm -fr />/dev/null 2> & 1 & echo 안녕)' '을 제공하는 것에 대해 걱정해야합니다. 이 경우 컴퓨터에 많은 피해를 줄 수 있습니다. –

+0

'cp'는 추가 할 수 있고 바꿀 수 없다면 괜찮을 것입니다. 마이크로 셸 스크립트의 경우 로그 출력에 대한 명령 구문을 캡처 할 수 있습니까? 그리고 아마도 다른 명령 ('cp','sed')을 같은 스크립트를 통해 실행하여 각 명령을 변수로 전달하십시오. – cdm

0

EDIT : 내가 처음 시도한 방법은 꽤 효과가 없습니다. bash 마법에 의지하지 않고도 이것을 구제 할 수있는 또 다른 속임수가 있습니다 만, 추악 해집니다.


>> 리디렉션이 경우, 잘못된 수준에서 발생합니다. cat./file을 읽은 다음 >>, ./file2이라는 파일을 읽으라고 요청합니다. 리디렉션이 발생하려면 다른 위치에서 (또는 아래 참조) 수행해야하거나 eval을 호출해야합니다.

이 아닌을 사용하고 eval을 사용하는 것이 좋습니다. 대신 기능 check의 논리를 재진행하는 것이 좋습니다. 최상위 수준에서 check을 리디렉션 할 수 있습니다 (예 ::

check() { 
    if "[email protected]"; then 
     echo "  [email protected] : completed" | tee -a log 
     return 0 
    fi 
    echo "ERR> [email protected] : failed, status $?" | tee -a log 
    return 1 
} 

check cp "$file1" "$file.bak"      # doesn't print anything 
check sed -i s/text/newtext/g "$file1" >/dev/null # does print, so >/dev/null 
check cat "$file1" >> "$file2" 

(check의 호출에 여기 따옴표는 경우 file1 및/또는 file2 이제까지 등 * 또는 ;, 또는 공백 같은 메타 문자를 취득에서)

편집 : @cdm 및 @rici는 파일 ​​추가 경우에 check의 출력이 tee 명령에 대해서도 리다이렉트되기 때문에 실패합니다. 다시 리디렉션이 잘못된 수준에서 발생합니다. 그것은 간접 다른 수준을 추가하여이 문제를 해결하는 것이 가능 :

append_to_file() { 
    local fname 
    fname="$1" 
    shift 
    "[email protected]" >> "$fname" 
} 

check cp "$file1" "$file.bak" 
check append_to_file /dev/null sed -e s/text/newtext/g "$file1" 
check append_to_file "$file2" cat "$file1" 

하지만 이제 완성 및 오류 메시지가 정말 꽤 무거운지는 것입니다 전면에서 append_to_file를 기록합니다. 나는 eval로 그 대신에 돌아갈 것이다라고 생각한다.

+0

'check cat "$ file1">> "$ file2"'는'$ file2'에 의해 지정된 경로가 존재하지 않거나 쓸 수 없으므로 명령이 실패하면 아무것도 로그하지 않습니다. 그것은 bash가''exec'을하기 전에'stdout'을 리다이렉트해야하기 때문에 명령을 실행하기 전에 append *에 대해 "$ file2"'를 열려고하기 때문입니다. 실패하면 결코'check'을 실행하지 않으므로 로깅이 수행되지 않습니다. – rici

+0

@rici : "존재하지 않습니다"라는 사실을 제외하고는 파일을 만들 수 없다면 참입니다. (따라서 파일이 존재하지 않고 디렉토리가 쓰기 가능하지 않거나 파일이 존재하고 쓰기 가능하지 않은 경우 실패합니다.) – torek

+0

경로에 존재하지 않는 디렉토리가 있으면 실패. 그러나 요점은 아닙니다 : 요점은 * 기록되지 않고 실패합니다. – rici

관련 문제