각 디렉터리를 읽고 Bash 스크립트에서 작업 수행

각 디렉터리를 읽고 Bash 스크립트에서 작업 수행

다음 디렉토리 구조가 있습니다 /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.phpreplicator디렉토리에는 이라는 스크립트가 있습니다 Replicator.php. 매일 밤 해당 스크립트를 실행해야 합니다. Replicator.php오전 00:00에 실행되어야 하며 sync.php오전 12:30에 실행되어야 합니다. 나는 여기서 올바른 경로가 분명히 cron 작업이라는 것을 알고 있습니다. 저는 두 개의 스크립트를 만들었고 거의 동일한 코드를 공유 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다음 해당 상위 디렉터리로 이동하여 php. crontab에 직접 명령을 추가할 수 있습니다.

0 30 * * * find /var/sync/ -name 'sync.php' -execdir php {} \;
0 0 * * * find /var/sync/ -name 'Replicator.php' -execdir php {} \;

Replicator30분 간격으로 스크립트를 실행 해야 하는 경우 다음과 같이 할 수 있습니다.

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 {} \;

따라서 쉘 스크립트를 호출하면 쉘은 $0C 프로그램이 설정하는 것처럼 특수 쉘 매개변수를 자신이 읽는 스크립트의 이름으로 설정합니다 argv[0]. 각각 랩 대상의 이름을 딴 두 개의 스크립트를 실행하고 있다는 점에서 이미 절반쯤 왔습니다. 하지만 이름이 두 개인 경우에는 두 개의 스크립트가 필요하지 않습니다. 따라서 동일한 스크립트를 두 번째 이름에 심볼릭 링크하고 $0호출할 때 참조할 수 있습니다.

cron당신에게만 필요하기 때문에

i=-30
for  s in sync replicator
do   echo "0 $((i+=30)) * * * /var/sync/$s.sh" | crontab
done

관련 정보