나는 다음과 같은 디렉토리 구조를 가지고 있습니다 /var/sync
.
# tree -d /var/sync/
/var/sync/
├── sync_bi
│ ├── replicator => Replicator.php
│ sync.php
├── sync_pfizer
│ ├── replicator => Replicator.php
│ sync.php
│ replicator.sh
│ sync.sh
보시다시피, sync_*
각 디렉토리에 이름이 붙은 스크립트가 있고 sync.php
, replicator
각 디렉토리에 이름이 붙은 스크립트가 있습니다 Replicator.php
. 매일 밤 이 스크립트를 실행해야 합니다. Replicator.php
오전 00:00에 실행되어야 하며 sync.php
오전 12:30에 실행되어야 합니다. 여기서 올바른 경로는 분명히 크론 작업이라는 것을 알고 있습니다. 두 개의 스크립트를 만들었고 거의 동일한 코드를 공유 replicator.sh
하는데 sync.sh
, 가장 큰 차이점은 스크립트 이름입니다. 아래 코드를 참조하세요.
replicator.sh
#! /bin/bash
cd $1
/usr/bin/php Replicator.php
sync.sh
#! /bin/bash
cd $1
/usr/bin/php sync.php
그런 다음 다음과 같이 cronjob에 각각을 추가합니다.
0 0 * * * /var/sync/replicator.sh /var/sync/sync_bi/replicator/
0 30 * * * /var/sync/sync.sh /var/sync/sync_bi/
0 2 * * * /var/sync/replicator.sh /var/sync/sync_pfizer/replicator/
30 2 * * * /var/sync/sync.sh /var/sync/sync_pfizer/
이러한 모든 설명의 기본 아이디어는 스크립트를 한 번의 cronjob 호출로 모든 작업을 수행하고 유지 관리할 파일 수를 줄이도록 허용하는 스크립트로 변경하여 환경을 최적화하는 것입니다. 그래서 저는 몇 가지 조사를 했고 몇 가지 유용한 주제를 찾았습니다.
- 내가 사용한
find some/dir -type f -execdir somecommand {} \;
것과 동일한 것을 달성하는 올바른 방법입니까?cd
그리고 루트 경로 아래의 각 디렉토리로 이동합니다. 제 경우에는
/var/sync
for D in ./*; do if [ -d "$D" ]; then cd "$D" run_something cd .. fi done
내가 말하는 의사코드는 다음과 같습니다(충분히 명확하지 않은 경우를 대비해).
read tree structure at /var/sync
foreach (directory in root+path)
if (directory_name is replicator)
cd replicator/
/usr/bin/php replicator.php
else if (directory_name is sync_*)
cd sync_*/
/usr/bin/php sync.php
endforeach
저는 bash 전문가가 아니기 때문에 의사 코드를 제가 원하는 것을 달성할 수 있는 기능적인 것으로 번역하는 데 도움을 요청하고 있습니다. 어떤 제안 및/또는 도움이 있습니까?
고쳐 쓰다
제가 틀렸을 수도 있지만 여러분이 하려는 일을 전혀 따르지 않습니다. 따라서 이벤트 순서는 다음과 같습니다.
# Run Replicator at mid day and mid night
# this two can run at same time since they are pushing data to different DBs
/var/sync/sync_bi/replicator/Replicator.php
/var/sync/sync_pfizer/replicator/Replicator.php
# Run sync at mid day and mid night
# this two should run one first and the second after 30 min since they are
# pushing data to the same DBs and second depends on first one
/var/sync/sync_bi/sync.php
/var/sync/sync_pfizer/sync.php
이 정보를 고려했을 때(먼저 알아내지 못해 죄송합니다) 솔루션이 어떻게 작동할까요? 지금 이미 가지고 있기 때문에, 아니면 이 문제를 해결하기 위해 무엇이든 변경해야 합니까?
답변1
그러면 의사코드가 bash로 변환됩니다.
#!/bin/bash
cd /var/sync
for dir in sync*/ ; do
( # Subshell to make "cd" not global.
cd "$dir"
[[ -f sync.php ]] && /usr/bin/php sync.php
if [[ -d replicator ]] ; then
cd replicator
[[ -f replicator.php ]] && /usr/bin/php replicator.php
fi
)
done
그러나 sync.php와 Replicator.php를 모두 실행하지만 원래는 서로 다른 시간에 호출하기를 원했습니다. 어쩌면 좋아
#!/bin/bash
run=$1
cd /var/sync
for dir in sync*/ ; do
( # Subshell to make "cd" not global.
cd "$dir"
[[ -f "$run" ]] && /usr/bin/php "${run##*/}"
)
done
다음과 같이 cron에서 호출됩니다.
0 30 * * * /path/to/script.sh sync.php
0 0 * * * /path/to/script.sh replicator/Replicator.php
${run##*/}
마지막 것 이전의 모든 것을 제거합니다 /
. 즉, 기본 이름만 반환됩니다.
고쳐 쓰다
다음과 같이 스크립트를 실행하려는 경우:
0:00 sync_a/sync.php
0:30 sync_a/replicator/Replicator.php
1:00 sync_b/sync.php
1:30 sync_b/replicator/Replicator.php
2:00 sync_c/sync.php
...
잠깐, 디렉토리 구조를 변경할 때마다 crontab을 다시 생성할 수 있습니다.
#!/bin/bash
add=$1
php=/usr/bin/php
hour=0
minute=0
update_time () {
(( minute += add ))
if (( minute >= 60 )) ; then
(( hour += minute / 60 ))
(( minute %= 60 ))
fi
if (( hour > 11 )) ; then
echo "Can't fit into a day!"
exit 1
fi
}
cd /var/sync
for dir in sync*/ ; do
if [[ -f "$dir"/sync.php ]] ; then
echo $minute $hour 0 0 0 "$php" /path/to/run.sh "$dir" sync.php
update_time
if [[ -f "$dir"/replicator/Replicator.php ]] ; then
echo $minute $hour 0 0 0 "$php" path/to/run.sh "$dir" Replicator.php
fi
update_time
fi
done
부르 generate_crontab.sh 30
거나 비슷합니다. 파일이 알파벳순으로 정렬되므로 일부 디렉터리는 변경 후 건너뛸 수 있습니다.
run.sh
그냥 해야 해
dir=$1
script=$2
if [[ -f "$dir$script" ]] ; then
cd "$dir"
/usr/bin/php $script
fi
답변2
가장 간단한 방법은 두 가지 find
명령입니다.
find /var/sync/ -name 'sync.php' -execdir php {} \;
find /var/sync/ -name 'Replicator.php' -execdir php {} \;
sync.php
그러면 이름이 지정된 파일을 찾 거나 Replicator.php
상위 디렉토리로 cd하여 php
. crontab에 직접 명령을 추가할 수 있습니다.
0 30 * * * find /var/sync/ -name 'sync.php' -execdir php {} \;
0 0 * * * find /var/sync/ -name 'Replicator.php' -execdir php {} \;
스크립트 사이에 30분 간격으로 스크립트를 실행 해야 하는 경우 Replicator
다음을 수행할 수 있습니다.
find /var/sync/ -name 'Replicator.php' -execdir php {} \; -exec sh -c "sleep 30m" \;
그러면 스크립트가 먼저 실행되고 30분 정도 기다린 후 다음 스크립트로 넘어갑니다.
sync.php
마지막으로 i) >1이 동시에 실행되지 않고 ii) sync
해당 스크립트가 완료된 후 각 스크립트가 실행되는지 확인해야 하는 경우 replicator
다음을 cron 명령으로 사용할 수 있습니다.
find /var/sync/ -name 'Replicator.php' -execdir php {} \; ; find /var/sync/ -name 'sync.php' -execdir php {} \;
위 코드는 먼저 각 Replicator.php
스크립트를 실행하고(병렬이 아닌 하나씩) 완료되면 각 sync.php
스크립트를 실행합니다.
답변3
{ cat > sync.sh
ln -s sync.sh replicator.sh
chmod +x sync.sh
} <<""
#!/bin/sh
cmd=${0%.*}
cmd=${cmd##*/}
find /var/sync -name "$cmd.php" -exec /usr/bin/php {} \;
따라서 쉘 스크립트를 호출할 때 쉘은 $0
C 프로그램과 마찬가지로 특수 쉘 인수를 읽는 스크립트의 이름으로 설정합니다 argv[0]
. 랩 대상의 이름을 따서 각각 이름이 지정된 두 개의 스크립트를 실행하고 있으므로 이미 절반쯤 왔습니다. 그러나 이름이 두 개인 경우 두 개의 스크립트가 필요하지 않습니다. 따라서 동일한 스크립트를 두 번째 이름에 심볼릭 링크하고 $0
호출할 때 이를 참조할 수 있습니다.
왜냐하면 cron
당신은 단지 필요하기 때문에
i=-30
for s in sync replicator
do echo "0 $((i+=30)) * * * /var/sync/$s.sh" | crontab
done