쉘 스크립트는 모든 하위 디렉토리에 대해 쉘 스크립트를 실행합니다.

쉘 스크립트는 모든 하위 디렉토리에 대해 쉘 스크립트를 실행합니다.

일상적인 작업을 단순화하기 위해 스크립트를 만들고 있습니다. 매일 회사 서버 내에서 무언가를 검색해야 합니다. 괜찮습니다. 하지만 이제는 각 개체를 하위 디렉터리로 분리했습니다. 저는 기존 쉘 스크립트가 특정 디렉토리 내의 모든 하위 디렉토리에서 반복적으로 실행되는 솔루션을 찾고 있습니다. 어떻게 해야 하나요? 저는 Linux를 처음 접했고 아직 배우고 있습니다.

이것은 내 스크립트입니다.

#!/bin/bash
MainDir=/path/to/dir/containing/subdirs
# cd into dir
cd $MainDir

for dir in $(ls); do

#fetch start time of uut
grep -i "01_node_setup" $dir/his_file | tail -1 >> /home/xtee/sst-logs.out

#check if sysconfig.out exists
if [ -f $dir/sysconfig.out];
then
    grep -A 1 "Drive Model" $dir/sysconfig.out | tail -1 >> /home/xtee/sst-logs.out
else
    grep -m 1 "Pair0 DIMM0" $dir/node0/trans_file_prev/*setupsys* | tail -1 >> /home/xtee/sst-logs.out
fi

done

#cd back to where we started
cd $OLDPWD

좋은 사람이 제가 대본을 작성하는 데 도움을 주었고 그렇게 해서 위의 대본이 나왔습니다. 그러나 binary file /some/subdirectory/grep 출력 대신 sst-logs.out 파일을 표시하여 잘 작동합니다 . 스크립트에 어떤 문제가 있나요?

답변1

찾기를 통해 다음을 구할 수 있습니다.

find /your/dir/with/subdirs -type d -exec sh -c 'cd "{}" ; /path/to/your/script.sh ;' \;

답변2

스크립트에 몇 가지 문제가 있습니다.

cd $MainDir

이렇게 하는 것이 좋습니다 cd "$MainDir". 중요하지는 않지만 발전하는 데 좋은 습관입니다. 변수가 따옴표 없이 확장되면 변수의 값이 단어로 분할되고 각 단어는 쉘 와일드카드 패턴으로 처리됩니다. 따라서 $MainDir공백이 포함되어 있거나\[?* 파일 이름이 일치하는 경우 큰따옴표를 추가해도 문제가 없습니다. 이러한 추가 확장을 피할 수 있습니다. 명령 대체( )의 경우에도 마찬가지입니다 $(somecommand).변수 및 명령 대체에는 항상 큰따옴표를 사용하십시오.분할과 파일 이름이 일치하길 원하는지 모르는 경우.

for dir in $(ls); do

출력을 구문 분석하지 않습니다.ls. ls스크립트에서 이를 사용할 필요가 거의 없습니다 . 위에서 언급한 대로 명령 대체 결과는 와일드카드 패턴으로 처리되는 단어로 분할되므로 인쇄할 수 없는 문자가 깨질 가능성이 있을 $(ls)뿐만 ls아니라 공백과 와일드카드도 깨집니다. 셸에는 디렉터리에 파일 이름을 나열하는 기능이 내장되어 있습니다.

for dir in *; do

이렇게 하면 for dir in */; do현재 디렉터리의 하위 디렉터리만 일치하고 다른 유형의 파일은 일치하지 않습니다.

if [ -f $dir/sysconfig.out];

옆에 있는 문자가 쉘 구두점인 경우를 제외하고 대괄호 양쪽에 공백이 필요합니다: ();&|<>. 다시 한 번, 변수 대체 주위에 큰따옴표를 넣으십시오(이는 변수 대체가 있는 다른 모든 위치에 적용됩니다).if [ -f "$dir/sysconfig.out" ];

#cd back to where we started
cd $OLDPWD

이것은 쓸모가 없습니다. 프로세스가 종료되려고 하며 현재 디렉터리를 변경해도 아무 영향이 없습니다. 각 프로세스에는 고유한 현재 디렉토리가 있습니다. 스크립트 내에서 이를 변경해도 스크립트를 호출하는 프로그램에는 영향을 미치지 않습니다.


질문하신 이유로 돌아가서 원하는 것이 무엇인지 명확하지 않습니다. " binary file /some/subdirectory/"는 별로 의미가 없습니다. 디렉토리와 함께 이 메시지를 받지 못할 것입니다. 더 나은 도움을 받으려면 오류 메시지를 복사하여 붙여넣으세요. 당신은해야항상 복사 붙여넣기 오류 메시지온라인으로 도움을 요청할 때.

귀하의 설명에 따르면 파일이 한 디렉터리 더 깊은 것 같습니다. 이 경우 행을 다음 for dir in */; do으로 변경하십시오.

for dir in */*/; do

답변3

이를 수행하는 방법에는 여러 가지가 있습니다. for 루프에서 기존 스크립트를 실행하거나 find 및 xargs를 사용하거나 grep의 -r일명 --recursive옵션을 사용할 수도 있습니다.

가장 간단한 방법은 아마도 기존 스크립트 주위에 for 루프 래퍼를 작성하는 것입니다. 예를 들어:

#! /bin/bash
cd /path/to/top/level/directory

for d in */ ; do 
  pushd $d
  # call your script here
  popd
done

답변4

find@rush의 제안이 약간 개선되어 스위치를 사용하는 대신 다음을 수행하면 명령 추가를 피할 수 있습니다 .-execcd

find /path/to/dir/containing/subdirs -type d -execdir /path/to/your/script.sh \;

이렇게 하면 for원본 스크립트의 루프를 완전히 피할 수 있습니다.

관련 정보