폴더에 파일이 있는지 그리고 파일이 안정적인지 확인하는 다음 스크립트가 있습니다(이것은 제가 받는 대용량 비디오 파일에 대한 것입니다).
#!/bin/bash
cdate1=$(date +%Y%m%d-%T)
folder1="/path-to-folder"
cd $folder1
while file=$(ls "$folder1")
[ -z "$file" ]
do sleep 10
done
echo "There is a file in the folder at $cdate1"
size1=$(stat -c '%s' "$file")
echo "The size1 is $size1"
sleep 30
size2=$(stat -c '%s' "$file")
echo "The size2 is $size2"
if [ $size1 = $size2 ]
then
ls -l
echo "Start converting"
else
echo "Restart the script"
fi
동일한 폴더에 있는 여러 파일을 확인하고 모든 파일이 안정되면 변환 스크립트를 시작하도록 스크립트를 수정하려면 어떻게 해야 합니까?
답변1
스크립트에는 다음과 같은 여러 가지 문제가 있습니다.
folder1="path-to-folder"
cd $folder1
while file=$(ls "$folder1") ...
사실입니다 cd path-to-folder; ls path-to-folder
. path-to-folder
절대 경로(예에서처럼 "/"로 시작)인 경우 작동할 수 있지만 상대 경로를 사용하는 한 작동하지 않습니다. 또한 공백을 포함하는 경우에도 작동하지 않습니다 path-to-folder
. 예를 들어 모든 곳에 따옴표를 사용해야 하기 때문입니다.cd "$folder1"
그런 다음 a를 실행하면 항상 다음으로 설정되므로 while file=$(ls ...)
무한 루프가 수행됩니다.file
무엇(디렉토리 내용).
올바른 구문은 for file in $(ls ...)
파일 이름에 공백이 있으면 작동을 중지한다는 것입니다( 이름이 파일인 경우 foo
루프 가 실행되기 때문입니다 ). 왜 해야 하는지 확인해보세요bar
foo bar
ls의 출력을 구문 분석하지 마십시오.. 을 사용하는 대신 ls
간단하게 for file in *
.
마지막으로 파일 크기가 더 이상 변경되지 않더라도 파일이 변경될 수 있습니다.
파일을 반복하는 좋은 방법은 find
파일이 변경되었는지 확인하는 좋은 방법입니다 mtime
.
다음 함수는 특정 디렉터리에 있는 모든 파일의 마지막 수정 시간(mtime) 값을 제공합니다.
folder1="/path-to-folder"
find "${folder1}" -exec stat -c "%Y" \{\} \; \
| sort -n | tail -1
따라서 스크립트는 다음과 같습니다.
#!/bin/bash
dir="$1"
# check whether $dir exists
test -d "${dir}" || exit 1
last=0
current=1
while [ "$last" != "$current" ]; do
last=$current
current=$(find "${dir}" -exec stat -c "%Y" \{\} \; \
| sort -n | tail -1)
sleep 10
done
echo "directory is now stable..."
고쳐 쓰다
더 나은 접근 방식은 특정 파일이 전송되었음을 수신자에게 사전에 알리는 것입니다. 매우 간단한 해결책은 페이로드가 전송된 후 빈 더미 파일을 복사하는 것입니다. 예를 들어 foo.avi
"다른 파일 복사"라는 파일 의 경우 해당 파일이 준비되었는지 확인 foo.avi.copyfinished
하기만 하면 됩니다 .foo.avi.copyfinished
foo.avi
while true; do
for file_ready in *.copyfinished; do
file=${file_ready%.copyfinished}
if [ -e "${file}.converted" ]; then
echo "skipping already converted file ${file}" 1>&2
else
touch "${file}.converted"
do_convert "${file}"
fi
done
sleep 1
done
이 해결 방법에는 분명히 발신자의 협조가 필요합니다.
답변2
프로세스가 전송 완료 여부를 알고 있는 전송 측의 처리를 제어하는 것이 더 쉽습니다. 이렇게 하면 전송이 중단되지 않습니다.
파일을 임시 이름이나 디렉터리로 보냅니다. 전송이 완료된 후 파일을 올바른 위치로 이동하세요.
cp srcvideo.avi /folder1/srcvideo.tmp && mv /folder1/srcvideo.tmp /folder1/srcvideo.avi
그러면 스크립트에서 차원에 대한 모든 테스트를 수행할 필요가 없습니다. 올바른 파일이 나올 때까지만 기다릴 수 있습니다.
cd /folder1 || exit 1
for file in *.avi; do
echo "$file found"
do_some_processing "$file"
done
원하는 경우 파일 이름을 변경하지 않고 별도의 전송 디렉터리를 사용하여 동일한 목적을 달성할 수 있습니다.
답변3
파일 성장이 멈출 때까지 기다리는 것은 다운로드가 완료되었는지 감지하는 좋은 방법입니다. 네트워크 장애로 인해 다운로드가 너무 오랫동안 일시 중지되면 스크립트가 시작됩니다.
다운로드가 완료된 후 일부 작업을 수행하는 가장 좋은 방법은 다운로드가 완료되어 성공할 때 스크립트를 실행하도록 다운로더에 지시하거나, 다운로더가 종료될 때까지 기다렸다가 다운로드가 성공하면 스크립트를 실행하도록 지시하는 것입니다. 괜찮은 다운로더라면 이러한 옵션 중 적어도 하나를 허용할 것입니다.
일부 열악한 다운로드 방법을 사용하는 경우 파일을 수동으로 보는 대신 알림 도구를 사용하여 파일 다운로드가 완료될 때 반응하십시오. Linux에서 알림 도구는 다음과 같습니다.inotify. 다운로더 작동 방식에 따라 파일 닫기(다운로더가 최종 파일에 직접 쓰는 경우) 또는 이름 바꾸기(다운로더가 먼저 임시 파일에 쓴 다음 그 자리에서 이름을 바꾸는 경우)에 반응합니다.
쉘 도구를 사용할 수 있습니다inotifywait
파일 이벤트가 발생하면 반응합니다. 다음은 이름이 변경된 각 파일을 변환하는 예입니다.
cd /path/to/directory
inotifywait -m -e moved_to --format=%f . |
while IFS= read -r filename; do
conversion-program "$filename"
done
답변4
모든 파일이 존재하는지 알기 전에 스크립트를 시작하려면 먼저 파일 수가 일정한지 확인하십시오. 다음을 사용하여 비슷한 작업을 수행할 수 있습니다.listfile = $(ls "$folder")
[ $( echo $listfile | wc -w) != $(ls "$folder" | wc -w) ]
while 루프에서는 상황이 동일하지 않을 때까지 $listfile
로 재설정됩니다 $(ls "$folder")
. 작업이 완료되면 한 파일에서 수행한 작업을 수행하는 do
루프 를 간단히 실행할 수 있습니다. 작업이 완료되면 변환을 시작할 수 있습니다.$listfile