각 줄에 데이터 파일 다운로드 명령을 실행하는 "명령" 텍스트 파일이 있습니다. 명령 파일을 bash로 보냅니다. 그러나 소수의 다운로드가 실패합니다. 누락된 항목을 찾는 데 사용하는 알고리즘은 다음과 같습니다.
- 다운로드 후 명령 파일로 돌아가서 다운로드한 각 파일이 존재하는지 확인합니다.
- 다운로드가 없으면 명령줄을 새 명령 파일에 복사합니다.
- 나머지 다운로드를 위해 새 명령 파일을 남겨 두었습니다.
다음은 알고리즘을 구현하는 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
일반적으로 말하면, 인용은 입니다.모두필드 분할을 원하는 경우가 아니면 매개변수 확장(변수 포함)입니다.