입력 파일을 처리할 때 복사/업데이트 및 이름 바꾸기가 효율적인 접근 방식입니까?

입력 파일을 처리할 때 복사/업데이트 및 이름 바꾸기가 효율적인 접근 방식입니까?

2개의 파일을 입력으로 사용하는 스크립트가 있습니다.
처리를 시작하려면 먼저 파일 준비가 필요합니다.
내 생각은 원본 파일을 건드리지 않고 모든 것을 복사본으로 만들고 출력으로 필요한 것을 인쇄하고 복사본을 삭제하는 것입니다.
그러나 이 접근 방식을 사용하면 스크립트에 변수가 많아지고 오류가 발생하기 쉽습니다.
예:

#!/bin/bash                                                                                                      
[[ -z $1 ]] && echo 'We need input file a' && exit 1;  
[[ -z $2 ]] && echo 'We need input file b' && exit 1;  

A_CSV=$1;  
B_CSV=$2;  

A_FILE="$A_CSV.tmp";  
B_FILE="$B_CSV.tmp";  

[ -f $A_FILE ]] && rm $A_FILE;  
[[ -f $B_FILE ]] && rm $B_FILE;  

tr -d "\r" < $A_CSV >  $A_FILE;  
tr -d "\r" < $B_CSV > $B_FILE;  

awk '{ if(NR == 1) sub(/^\xef\xbb\xbf/,""); print }' $A_FILE > "$A_FILE.bck";
awk '{ if(NR == 1) sub(/^\xef\xbb\xbf/,""); print }' $B_FILE > "$B_FILE.bck";

rm $A_FILE && mv "$A_FILE.bck" $A_FILE;   
rm $B_FILE && mv "$B_FILE.bck" $B_FILE;   
# extra logic following the same pattern  

계속해서 업데이트하고 이름을 바꾸기 위해 복사본이 어떻게 생성되는지 확인할 수 있습니다.

스크립트 오류를 ​​줄이기 위해 이를 개선할 수 있는 방법이 있습니까?

답변1

이는 |파이프()를 통해 달성됩니다. 세상에는 좋은 튜토리얼이 많이 있습니다. 이것.

#!/bin/bash
[[ -z $1 ]] && echo 'We need input file a' && exit 1;
[[ -z $2 ]] && echo 'We need input file b' && exit 1;  

A_CSV=$1;  
B_CSV=$2;  

A_FILE="$A_CSV.tmp";  
B_FILE="$B_CSV.tmp";  

[ -f $A_FILE ]] && rm $A_FILE;
[[ -f $B_FILE ]] && rm $B_FILE;

tr -d "\r" < $A_CSV | awk '{ if(NR == 1) sub(/^\xef\xbb\xbf/,""); print }' > $A_FILE
tr -d "\r" < $B_CSV | awk '{ if(NR == 1) sub(/^\xef\xbb\xbf/,""); print }' > $B_FILE

개인적으로 저는 두 파일에 대해 동일한 작업을 수행하므로 단일 작업을 처리하는 함수를 만들고 싶습니다. rm -f $A_FILE $B_FILE제 생각엔 보기에도 더 좋을 것 같아요.

답변2

원본 파일을 그대로 두고 복사본으로 작업하는 것이 매우 좋습니다. 한 단계 더 나아가 중간 ​​파일도 재사용하지 않아야 합니다. 중간 파일을 재사용하고 프로세스가 중단되면 어느 지점에서 중단되었는지 알 수 없습니다.

두 파일 모두에 동일한 변환을 적용하고 있습니다. 코드를 두 번 작성하지 마세요! 코드를 한 번 작성하고, 필요에 따라 변수를 사용하고, 각 파일에 대해 한 번씩 코드를 호출하세요. 쉘 스크립트에서 이를 수행하는 도구는 다음과 같습니다.기능(또는 여러 스크립트에서 이 코드 조각을 호출해야 하는 경우 별도의 스크립트로 만드세요.)

사용하는 모든 텍스트 처리 도구는 표준 입력에서 읽고 표준 출력에 쓸 수 있습니다. 배치하여 결합할 수 있습니다.관로한 도구의 출력과 다음 도구의 입력 사이. 이렇게 하면 중간 파일이 많이 필요하지 않습니다. 실제로 이 경우 중간 파일이 필요하지 않습니다. 파이프는 Unix의 기본 디자인 기능입니다.

추가 쉘 프로그래밍 팁:변수 확장 주위에는 항상 큰따옴표를 사용하세요., 즉 $foo.

#!/bin/bash                                                                                                      

preprocess_csv () {
  <"$1" \
  tr -d '\r' |
  awk '{ if(NR == 1) sub(/^\xef\xbb\xbf/,""); print }' >"${1%.csv}.clean"
}

preprocess_csv "$1"
preprocess_csv "$2"

do_stuff_with_preprocessed_file "${1%.csv}.clean" "${2%.csv}.clean" >global_output

내가 사용하는 것은매개변수 확장예를 들어 ${1%.csv}로 변환하여 이 변환의 출력 파일이 가 되도록 구성합니다 .foo.csvfoofoo.clean

이 스크립트는 귀하의 스크립트보다 간단하지만 여전히 개선될 수 있습니다. 파일 처리 명령 체인을 설명하는 데 쉘 스크립트보다 더 나은 도구가 있습니다.자동화 도구 구축클래식 같은만들다. 바라보다체크포인트를 사용하여 명령 목록을 실행하시겠습니까?유사한 사용 사례를 소개합니다. make를 사용하여 변환을 표현하는 방법은 다음과 같습니다. 이 파일을 호출하십시오 Makefile. 다음 줄은 8개의 공백으로 들여쓰기되어 있으며 이를 탭으로 바꿔야 합니다. 이는 make의 특이한 점입니다.

default: global_output

%.clean: %.csv
        <'$<' tr -d '\r' | awk '{ if(NR == 1) sub(/^\xef\xbb\xbf/,""); print }' >'$@'

global_output: input1.clean input2.clean
        do_stuff_with_preprocessed_files input1.clean input2.clean >$@

$<명령에서 종속성(위 오른쪽 파일 target: dependency) 을 나타내고 $@대상을 나타냅니다. 위의 makefile을 사용하여 명령을 실행하면 (또는 시작 부분의 행 덕분에 make global_output명령만 실행하면 ) 변환을 실행하여 파일을 생성한 다음 ( 파일이 이미 존재해야 함) 생성을 위해 실행됩니다. .​makedefault:.clean.csvdo_stuff_with_preprocessed_filesglobal_output

이 메이크파일은 중간에 중단되면 부분적으로 처리된 파일을 남기기 때문에 취약합니다. 이 문제를 해결하려면 다음 설명에 따라 각 규칙에 임시 파일을 사용하세요.체크포인트를 사용하여 명령 목록을 실행하시겠습니까?.

default: global_output

%.clean: %.csv
        <'$<' tr -d '\r' | awk '{ if(NR == 1) sub(/^\xef\xbb\xbf/,""); print }' >'[email protected]'
        mv '[email protected]' '$@'

global_output: input1.clean input2.clean
        do_stuff_with_preprocessed_files input1.clean input2.clean >'[email protected]'
        mv '[email protected]' '$@'

관련 정보