목록을 기반으로 파일이 존재하는지 확인하십시오.

목록을 기반으로 파일이 존재하는지 확인하십시오.

각 줄에 데이터 파일 다운로드 명령을 실행하는 "명령" 텍스트 파일이 있습니다. 명령 파일을 bash로 보냅니다. 그러나 소수의 다운로드가 실패합니다. 누락된 항목을 찾는 데 사용하는 알고리즘은 다음과 같습니다.

  1. 다운로드 후 명령 파일로 돌아가서 다운로드한 각 파일이 존재하는지 확인합니다.
  2. 다운로드가 없으면 명령줄을 새 명령 파일에 복사합니다.
  3. 나머지 다운로드를 위해 새 명령 파일을 남겨 두었습니다.

다음은 알고리즘을 구현하는 bash 스크립트입니다.

  1 #!/bin/bash
  2 while read line
  3 do
  4         for item in $line
  5         do
  6                 if [[ $item == *out_fname* ]]; then 
  7                         splitline=(${item//=/ })   
  8                         target_file=${splitline[1]}
  9                         if [ ! -f $target_file ]; then
 10                                 echo $line >> stillneed.txt
 11                         fi
 12                 fi
 13         done
 14 done < "$@"

질문: 이것은 훌륭하게 작동하지만 더 나은 알고리즘이나 구현이 있습니까(어쩌면 bash 이외의 다른 것을 사용할 수도 있음)? 내가 한 일은 인간이 해야 할 일을 bash에게 맡기는 것뿐이었습니다. 하지만 유닉스는 항상 일을 처리하는 더 나은 방법을 갖고 있는 것 같습니다...

답변1

"out_fname"뿐만 아니라 "out_fname="을 찾고 있는 것 같습니다.

나는 awk와 shell을 혼합하여 사용하거나 Python을 사용합니다. awk/셸에서:

awk '{for(i=0;i<NF;i++) {if (index($i, 'out_fname=')) {split($i,A,/=/);print A[i]}}' "$@" |
    while read filename; do
        if [ ! -f $filename ]; then echo $filename; fi
    done > stillneed.txt

파이썬에서는:

import fileinput, os
stillneed = open("stillneed.txt", "w")
for line in fileinput.input():
    for filename in [l.split('=')[1] for l in line.split() if l.find('out_fname=')!=-1]:
        if not os.path.exists(filename):
            print >>stillneed, filename

답변2

도움이 될지는 모르겠지만 성공할 때까지 명령을 재시도하는 함수가 있습니다.

retry () {
    local delay=1 n

    if ! [[ $1 = *[^0-9]* ]]; then
        # TODO allow delay=0 (prevents Ctrl-C)
        if (($1 > 0)); then
            delay=${1:1}
        fi
        shift
    fi

    # run command
    while ! "$@"; do
        echo "retrying in ${delay}s"
        for ((n=delay; n>0; n--)); do
            sleep 1 || return
        done
    done
}; export -f retry

답변3

초기 다운로드 스크립트가 완료된 후 누락된 콘텐츠를 확인하는 대신 해당 다운로드 스크립트에 몇 가지 검사를 추가하는 것이 좋습니다. 다음 내용은 테스트하지 않고 그냥 머리 속에 썼습니다.

cat files_to_download|while read file; 
do
    SUCCESS="False"
    while [[ $SUCCESS == "False" ]];
    do
        wget $file;
        if [[ $? -eq 0 ]];
        then
            SUCCESS="True"
        fi
   done
done

답변4

echo이후에 파일의 각 줄을 구문 분석하여 파일 이름을 확인하는 것보다 다운로드가 실패할 때 해당 줄을 복사하는 것이 좋습니다 .

[[ -f $1 ]] || { echo "$1 not found" >&2; exit 1; }
while read -r line; do
    $line || echo "$line" >> stillneed
done < "$1"

이는 더 효율적이며 나중에 이상한 파일 이름(예: 공백 포함)에 대해 걱정할 필요가 없음을 의미합니다.

기존 방법을 개선하려면 표준 매개변수 확장을 사용할 수 있습니다.

for f; do
    while read -r line; do
        for item in $line; do
            [[ $item = out_fname=* ]] || continue
            [[ -f ${item#out_fname=} ]] || echo "$line"
            break # assuming one fname per line
        done
    done < "$f"
done > stillneed

..하지만 무슨 일이 일어나는지 생각해 보세요. out_fname='foo bar.ext'. 또한 이는 이벤트가 발생한 후 각 줄을 확인하는 반면, 명령을 실행할 때 명령이 유효한지 확인할 수 있다는 점을 기억하세요.

stillneed전체 루프를 한 번 여는 것이 더 효율적입니다. 다운로드 명령의 출력을 보고 싶을 가능성이 높기 때문에 첫 번째 코드 조각에서는 이 작업을 수행하지 않았습니다. 여기에는 테스트만 있고 외부 명령이 실행되지 않으므로 파일을 한 번 여는 것이 좋습니다. (사용하면 >처음에 파일이 잘립니다. 저는 for f여러 입력 파일을 위치 인수로 허용하곤 했습니다. 필요한 경우 위와 동일하게 추가하는 것이 쉬울 것입니다.)

제가 강조해야 할 한 가지는 인용입니다 echo "$line". echo $line일반적으로 말하면, 인용은 입니다.모두필드 분할을 원하는 경우가 아니면 매개변수 확장(변수 포함)입니다.

관련 정보