안녕하세요
pi에 다음과 같은 bash script를 작성해서 하루에 한번씩 실행시킬 생각입니다
스크립트는 일차로 new디렉토리를 검색해서 파일이 있으면 무조건 날짜순으로 선택해서 실행해준다음 arc디렉토리로 옮겨주고요,
new디렉토리가 비었으면 arc에서 랜덤하게 파일을 선택해서 실행합니다
눈치채신 분도 계시겠지만 전자액자를 어떻게 구현해볼까 하고 있습니다
며칠간 테스트해본 결과 최근 사진 위주로 잘 보여주고 최근사진이 다 떨어지면 지난 사진들을 랜덤하게 보여줘서 만족스런 편입니다
하나 문제는 arc에 있는 파일을 보여줄 경우 이게 랜덤이다보니 가끔 동일한 사진이 두번 연속으로 올라오는 경우가 있습니다
사진이 하루에 한번씩 바뀌는 컨셉인데 이틀 연속으로 같은게 올라오니 좀 그렇습니다
무슨 좋은 방법이 없을까요?
1. find 명령으로 현재보다 얼마간 이전에 수정/변경된 파일의 목록을 구한다. (파일이 하나도 없으면 시간범위를 조정한다.)
2. 파일 목록의 순서를 섞는다.
3. 파일을 보여준다.
4. touch 명령으로 파일의 수정/변경 시간을 바꾼다.
5. 목록에 파일 이름을 제거하고 3으로 간다.
정도면 될 것 같네요.
추가: 한 번 아래 코드를 시험해 보세요. (혹시... 잘 안될지도 몰라서요...) echo 문이 원하는대로 출력되면 명령으로 바꾸고요^^
cd /home/pi/Pictures
while true; do
NEW="$(find new -mindepth 1)"
ARC="$(find arc -mindepth 1 -mtime +1 | shuf)"
[ -z "${NEW}" ] && [ -z "${ARC}" ] && break
for file in ${NEW}; do
echo fbi -T 7 -d /dev/fb0 -noverbose -autozoom ${file}
echo mosquitto_pub -h 192.168.1.200 -p 1883 -t 'pictureFrame/filename' -m "$(basename ${file})"
echo touch ${file}
echo mv ${file} arc
echo sleep 1d
done
for file in ${ARC}; do
[ "$(ls -A new)" ] && break
echo fbi -T 7 -d /dev/fb0 -noverbose -autozoom ${file}
echo mosquitto_pub -h 192.168.1.200 -p 1883 -t 'pictureFrame/filename' -m "$(basename ${file})"
echo touch ${file}
echo sleep 1d
done
done
감사합니다! 스크립트가 아름답네요~
테스트삼아 에코를 다 지우고 sleep 1d를 1m으로 줄여서 실행시켜봤는데요
이게 한 사이클이 다 돌아가면 그냥 끝나버리네요
(테스트 폴더에는 이미지파일이 9개가 있는데 무슨 이유에선지 8개만 보여주고 종료해버립니다)
그리고 그 이후로는 실행시켜도 아무런 반응이 없습니다
저는 crontab으로 스크립트를 매일 아침에 한번 실행하게 했었는데,
위의 스크립트에서 sleep 1d만 없애고 크론으로 돌리면 뭐가 달라질까요?
"크론으로 돌리면 뭐가 달라질까요?" 이건... while true; do 줄과 맨 밑의 done 줄 사이의 내용을 무한 반복하는 코드에요^^. 또... NEW 와 ARC 도 한 개의 파일이 아니라 파일 목록이고요, for 문으로 반복하고 있어요. ARC 반복마다 new 디렉터리에 새 파일이 있는지 검사해서 break 하는 부분이 있고요, break 되면 while 반복으로 돌아가 새로운 NEW 반복을 하는 구조에요.
크론으로 돌린다면 중복 실행이 될 수 있겠네요TT. 조금 더 신경쓴다면... 스크립트의 내용을 실행하기 전에 같은 이름의 프로세스를 검사해서 이미 실행되고 있다면 즉각 종료하는 부분을 넣어주고, 시스템 기동시 런레벨의 서비스로 동작하도록 만들 것을 생각하고 있었던 것이거든요^^. 물론, 조금 더 다듬어야 되지만요. 만일 크론으로 돌린다면...
cd /home/pi/Pictures
FILE="$(find new -mindepth 1 | sort | head -n 1)"
DEST="arc"
if [ -z "${FILE}" ]; then
FILE="$(find ${DEST} -mindepth 1 -mtime +1 | shuf -n 1)"
DEST=""
fi
if [ "${FILE}" ]; then
fbi -T 7 -d /dev/fb0 -noverbose -autozoom ${FILE}
mosquitto_pub -h 192.168.1.200 -p 1883 -t 'pictureFrame/filename' -m "$(basename ${FILE})"
touch ${FILE}
[ "${DEST}" ] && mv ${FILE} ${DEST}
fi
정도로 바꾸면 한 개의 파일만 대상으로 한 번만 실행할거에요. 아... 머리 속으로만 짠 거라 시험을 해봐야해요^^.
이제 조금 이해가 가는군요 ㅎㅎ
8개만 실행됐던건 아마 new디렉토리내에 파일갯수와 관련이 있는것 같습니다. 스크립트가 new를 다 써버리면 종료되는것 같아요.
(테스트를 위해서 1분으로 시간간격을 줄였으니 find arc -mindepth 1 -mtime +1도 이에 맞게 고쳐 봐야 할까요?)
그리고 크론을 사용하는 이유는 fbi가 제 파이zw에서 좀 많이 불안정하드라구요... 테스트로 한 열번 연속 고해상도 이미지를 연속로딩하고 나면 무슨 이유에선지 뻗어버리더군요.
어차피 혼자쓰는 파이고 전자액자 외에 별 다른 특별한 기능을 하는게 아니라서 그냥 단순히 매일 새벽에 자동 리붓 시키고 크론으로 부팅후 30초 딜레이했다가 스크립트 실행하면 간단할 것 같아서였습니다. 이런 방식이면 말씀하신 프로세스 중복문제도 걱정할 게 없구요
어쨌든 touch로 파일시간을 변경시키는 방식이 제게는 아주 신박해서 이걸로 성공했으면 좋겠군요
arc 디렉토리에서 랜덤하게 선택된 파일명을 어디다 써두고(특정 파일에 기록?),
써둔 걸 읽어서 선택된 파일 명과 비교해서 같으면 한 번 더 랜덤하게 고르도록 하면 안될까요?
그것도 방법중 하나네요
일단 위의 예쁜닉네임님 방식이 별도 임시파일도 필요없고 깔끔해보여서 일단 그 방식 시도해보구요
초보수준에서 과하게 복잡해지면(!) 이방식도 검토해보겠습니다
1. 디렉터리를 3개 만든다. (new, todo, done)
2. new 와 todo 가 모두 비어있으면, todo 디렉터리를 지우고 done 의 이름을 todo 로 바꾼다. 새로운 디렉터리 done 을 만든다. (기존 done 은 todo 로 이름이 바뀌었으니까...)
3. new 디렉터리에 파일이 있으면... new 디렉터리에서 파일을 하나 골라 그 파일을 처리하고, 해당 파일을 done 디렉터리로 mv 한다. new 디렉터리에 파일이 없으면... todo 디렉터리에서 파일을 하나 골라 그 파일을 처리하고, 해당 파일을 done 디렉터리로 mv 한다.
cd /home/pi/Pictures
FILE="$(find new -mindepth 1 | sort | head -n 1)"
if [ -z "${FILE}" ]; then
FILE="$(find todo -mindepth 1 | shuf -n 1)"
[ "${FILE}" ] || rmdir todo || mv done todo || mkdir done || FILE="$(find todo -mindepth 1 | shuf -n 1)"
fi
if [ "${FILE}" ]; then
fbi -T 7 -d /dev/fb0 -noverbose -autozoom ${FILE}
mosquitto_pub -h 192.168.1.200 -p 1883 -t 'pictureFrame/filename' -m "$(basename ${FILE})"
mv ${FILE} done
fi
정도 될 것 같네요. 역시... 시험은 해보지 않았지만요.
옛날옛적 산수/수학시간에 '주머니에서 공을 꺼내서 색깔을 확인하고 다시 집어넣기/ 안 집어넣기' 확률 계산하던거랑 비슷하네요
결국 중복을 피하려면 주머니에 따로 담기만 하면 되니까 이게 젤 간단한 방법이겠군요
주머니가 비면 샥! 바꿔서 계속 돌려주면 되구요
여러 아이디어들 정말 감사합니다. 저는 주로 하드웨어/3D DIY가 취미인데 이런 초보 프로그래밍도 재미 차원에서 나쁘지않군요!
스크립트초반에 #!/bin/bash라는건 도대체 무슨 역할인걸까요?
인터넷으로 검색해보면 다들 저것부터 달고 시작해서 필수인줄 알았는데
위의 예쁜닉네임님 스크립트는 그것 없이도 잘만 돌아가는군요
다음으로... #!/bin/bash 라는 첫 줄은 https://ko.wikipedia.org/wiki/셔뱅 이라고 불러요. 어떤 해석기로 스크립트를 실행할 것인가를 명시적으로 지정해주는 것이고요. 지정하지 않으면 SHELL 환경변수로 지정되어있는 (대부분의 경우 /bin/bash 일테지만) 쉘로 해석할거에요. 이건, 명시적으로 지정하는 것이 좋아요. 이 경우는 본 쉘 스크립트지만... 스크립트라는 것이 본 쉘 스크립트만 있는 것은 아니거든요. 예를 들어, perl 이란 언어로 스크립트를 짤 수도 있겠죠. python 이란 언어로 짤 수도 있고요.
최근에는 bash말고 다른 shell을 쓰는 경우가 많아서 (fish나 zsh)
스크립트에 명시하는 것이 좋습니다.
if(arc.count !=1 && arc.count !=0) {
// 어제 본 파일명 뺀것들중 랜덤 선택
}