2010-04-16 6 views
0

나는 foo.xml 파일을 가져 와서 foo.txt 파일을 작성할 펄 스크립트 (또는 어떤 실행 파일)도 가지고있다. Beowulf 클러스터를 사용하여 많은 수의 XML 파일에 대해 E를 실행하지만 기존 txt 파일을 덮어 쓰지 않는 쉘 (bash)에 간단한 작업 서버 스크립트를 작성하고 싶습니다.쉘 스크립팅 : 검색/바꾸기 및 체크 파일이 존재 함

나는 현재

#!/bin/sh 
PATTERN="[A-Z]*0[1-2][a-j]"; # this matches foo in all cases 
todo=`ls *.xml | grep $PATTERN -o`; 
isdone=`ls *.txt | grep $PATTERN -o`; 

whatsleft=todo - isdone; # what's the unix magic? 

#tack on the .xml prefix with sed or something 

#and then call the job server; 
jobserve E "$whatsleft"; 

같은 것을하고 있어요 그리고 나는 $의 할 일 및 $의 isDone의 차이를 가져 오는 방법을 모른다. grep을 사용하여 for 루프 같은 것을 sort/uniq을 사용하는 것이 더 좋겠지 만, 어떻게해야 할 지 모르겠다. (파이프? 임시 파일?)

보너스 질문으로, bash grep에서 lookahead 검색? 나는 (반드시 그런 것은 아니지만) 데이터/{지점}/특수/{패턴} .XML 같은 소스로부터 입력을 다른 출력을 쓰기 프로그램의 무리가

:

는 확장/문제를 명확히하기 위해 디렉토리 결과/특수/{분기} - {패턴} .txt (또는 데이터/{분기}/중간/{패턴} .dat). 그 파일이 이미 존재한다면 jobfarming 쉘 스크립트를 체크인하고 싶습니다.

그래서 E는 데이터/{branch}/special/{pattern} .xml-> 결과/특수/{branch} - {pattern} .dat를 변환합니다. 각 입력 인스턴스를보고 출력이 존재하는지 확인하고 싶습니다. 이 작업을 수행하는 한 가지 방법은 각 입력 파일 옆의 * .done 파일을 터치하고 그 결과를 확인하는 것입니다. 그러나이를 관리하지 않는 것이 좋으며, 때로는 작업이 부적절하게 종료되어 필자가 원하지 않을 수도 있습니다. 완료로 표시됩니다.

N.B. 동시성을 확인하거나 파일을 잠글 필요가 없습니다.

그래서 (의사 코드) 위의 문제를 해결하기 위해 간단하고 명확한 방법은

for i in `/bin/ls *.xml` 
do 
    replace xml suffix with txt 
    if [that file exists] 
     add to whatsleft list 
    end 
done 

수 있습니다하지만 난 더 일반적인 뭔가를 찾고 있어요.

+0

'txtfile = $ {XMLFILE의 %의 .XML}는 대체됩니까 .txt' - 내 대답에있다. –

+0

"파일 덮어 쓰기를 피하려면"동시성을 인식해야합니까? 그렇다면 잠금을 수행해야합니다. (그렇다면 ... 우리는 공유 파일 시스템에 있습니까? 어느 것이 있습니까?'flock '에 대한 적절한 의미가 있습니까?) –

+0

동시성 인식이없고 잠금이 없습니다 - 공유 파일 시스템이지만 이것은 부수적 인 프로젝트입니다 for now – johndashen

답변

1
#!/bin/sh 

shopt -s extglob # allow extended glob syntax, for matching the filenames 

LC_COLLATE=C  # use a sort order comm is happy with 

IFS=$'\n'  # so filenames can have spaces but not newlines 
       # (newlines don't work so well with comm anyhow; 
       # shame it doesn't have an option for null-separated 
       # input lines). 

files_todo=(**([A-Z])0[1-2][a-j]*.xml) 
files_done=(**([A-Z])0[1-2][a-j]*.txt) 
files_remaining=(\ 
    $(comm -23 --nocheck-order \ 
    <(printf "%s\n" "${files_todo[@]%.xml}") \ 
    <(printf "%s\n" "${files_done[@]%.txt}"))) 

echo jobserve E $(for f in "${files_remaining[@]%.xml}"; do printf "%s\n" "${f}.txt"; done) 

이것은 당신이 인수로 남아있는 모든 파일과 하나의 jobserve E 전화를 원하는 가정; 그러한 경우에는 사양에서 다소 불명확합니다.

considered very poor practice 인 ls를 구문 분석하는 대신 확장 된 glob을 사용합니다.

쉘 내장 명령 이외의 것을 사용하지 않고 출력 이름에 입력을 변환하려면 다음을 고려하십시오

if [[ $in_name =~ data/([^/]+)/special/([^/]+).xml ]] ; then 
    out_name=results/special/${BASH_REMATCH[1]}-${BASH_REMATCH[2]}.dat 
else 
    : # ...handle here the fact that you have a noncompliant name... 
fi 
+0

멋진데. 나는 IFS 나 통신에 대해 몰랐다. shopt 및 LC_COLLATE 행의 기능을 설명 할 수 있습니까? – johndashen

+0

'shopt' 라인은 extglob 플래그를 설정합니다.이 플래그는 확장 된 glob 구문을 사용하여 파일을 일치시킵니다 (사실, 정규 표현식없이 관련 파일 만 일치 시키려고합니다). 'LC_COLLATE = C'는'glob' 파일에 대한 디폴트 정렬 순서를'comm'이 만족하게 할 것입니다. –

+0

'ls'에 대한 좋은 지적. 나는 그것을 'find'로 대체하는 것이 훨씬 간단하고 읽기 쉽다고 생각한다. – slacker

0

내가 원하는 것을 정확히 모르겠지만, 파일이 있는지 먼저 확인할 수 있습니다. 존재한다면 새로운 이름을 만드시겠습니까? (또는) 귀하의 E (펄 스크립트에이 확인을한다.)

if [ -f "$file" ];then 
    newname="...." 
fi 
... 
jobserve E .... > $newname 

는 당신이 원하는 것을, 더 명확하게 귀하의 질문에 당신이 "파일을 덮어 쓰지 않는다"무슨 뜻인지 설명하지 않으면 ..

+0

그게 내가 원하는 행동이지만, 나는 덮어 쓰지 않도록 perl 스크립트/실행 파일에 의존하고 싶지 않습니다. – johndashen

1

질문 제목은 당신이 찾고 될 수 있음을 시사 :

set -o noclobber 

질문의 내용이 전적으로 다른 문제가 있음을 나타냅니다!

일치하는 '.txt'파일없이 각 '.xml'파일에서 'jobserve E'를 실행하고 싶습니다. 클러스터 환경에 있기 때문에 TOCTOU (Time of Check, Time of Use) 문제를 평가해야합니다. 하지만 기본 아이디어는 다음과 같습니다 :

todo="" 
for file in *.xml 
do [ -f ${file%.xml}.txt ] || todo="$todo $file" 
done 
jobserve E $todo 

이것은 Bash뿐만 아니라 Korn 쉘에서도 작동합니다. Bash에서는 'todo'를 배열로 만들 수 있습니다. 이것은 파일 이름에서 공백을 더 잘 처리 할 것입니다.

여전히 '.txt'파일을 생성하는 프로세스가있는 경우.xml '파일을 검사 할 때 중복 된 노력이 필요합니다 (이 스크립트는 처리가 진행 중임을 알 수 없기 때문에). 'E'프로세스가 처리를 시작할 때 해당 '.txt'파일을 작성하면 기회 또는 중복 된 노력을 최소화합니다. 또는 처리되지 않은 파일에서 처리 된 파일을 분리하는 것을 고려하십시오. 'E'프로세스가 '.xml'파일을 '완료'디렉토리에서 '완료된'디렉토리로 이동하고 '.txt' 'done'디렉토리에도 파일). 주의 깊게 수행하면 대부분의 다중 처리 문제를 피할 수 있습니다. 예를 들어 처리가 시작되면 '.xml'을 'done'디렉토리에 연결하고 'atexit()'처리기로 적절한 정리를 수행 할 수 있습니다 (처리 프로그램이 충돌하지 않는다고 보통 확신하는 경우). 또는 자신의 고안에 대한 다른 속임수.

+0

스크립트 E가 호출간에 겹치는 파일에 액세스하지 않으므로이 작업이 저에게 효과적입니다. 나는 bash 스크립팅을 처음 접했을 때 몇 가지 추가 질문이 있습니다. (1) for 절에서 여러 별표가있는 glob을 사용할 수 있습니까? \ */special/\ *. xml 같은 경우? (2) % 구문은 .xml의 모든 인스턴스를 제거합니까? – johndashen

+0

(1) 예; (2) 아니요. 단일 %는 마지막 '.xml'만 제거합니다 (따라서 x.xml.xml.xml -> x.xml.xml). –

1
whatsleft=$(ls *.xml *.txt | grep $PATTERN -o | sort | uniq -u) 

참고이 실제로 대칭 차이를 가져옵니다.

후손을 위하여
+0

이 예제에서는 나에게 도움이 될 것이지만 약간 간소화되었다. * .xml -> * - reordered.xml과 같은 다양한 패턴에 대해서도이 작업을하고 싶다. 이 경우 나는 ls를 --ignore와 함께 사용했다 :이를 수용하기 위해 명령을 수정할 수 있습니까? – johndashen

+0

@ johndashen : 왜 작동하지 않겠는가, 아니면 어쩌면 내가 무엇을 의미하는지 이해하지 못할 수도 있습니다. :) 예를 들어 좀더 명확하게 설명해 주실 수 있습니까? – slacker

+0

예제에서 * .txt를 * -reordered.xml로 대체하면 * -reordered.xml 사본을 두 번 얻을 수 있지만 uniq이 처리하므로 실제 문제는 아닙니다. 허. =) – johndashen

0

이 내가 일을 찾을 것입니다 :

TMPA='neverwritethis.tmp' 
TMPB='neverwritethat.tmp' 
ls *.xml | grep $PATTERN -o > $TMPA; 
ls *.txt | grep $PATTERN -o > $TMPB; 
whatsleft = `sort $TMPA $TMPB | uniq -u | sed "s/%/.xml" > xargs`; 
rm $TMPA $TMPB; 
+0

$ TMPA와 $ TMPB가 실제로 파이프로 명명 된 경우 더 멋있습니다. – slacker

+0

내가 준 임시 파일을 필요로하지 않으며, ('sort','uniq' 및'sed')보다는 하나의 외부 명령 ('comm')만을 사용합니다. –

관련 문제