Bash에서 디렉토리 항목을 반복하고 배열에 저장

Bash에서 디렉토리 항목을 반복하고 배열에 저장

(질문 하단의 업데이트를 참조하세요).

후속 질문입니다"디렉토리 복사본을 만들려면 찾기를 사용하세요.".

문제는 단일 명령으로 처리하기에는 너무 복잡한 여러 디렉터리를 조작하는 것과 관련이 있었기 때문에 이식성에 대한 약간의 유보가 있지만 디렉터리 목록을 bash 배열에 저장하는 방법을 결정했습니다. POSIX 쉘 표준(내가 아는 한 Unix 쉘 표준)에는 배열이 없는 것 같습니다.

내가 사용하는 makefile은 아래와 같습니다. 이것은 마지막 단계를 제외하고는 작동합니다. 내가하려는 일에 대한 요약은 다음과 같습니다.

이전 질문에서 설명한 것처럼 디렉터리를 반복하면서 x86-headers파일이 포함된 최상위 하위 디렉터리 목록을 bash 배열로 수집하고 싶습니다(다른 파일도 포함할 수도 있음). 예를 들어, 내 테스트 설정에는 파일을 포함하는 디렉터리 C/populate.sh가 하나만 있습니다 .x86-headerslibc/C/populate.shlibc

그런 다음 이러한 하위 디렉터리에 대해 몇 가지 작업을 수행합니다. 이들 중 가장 중요한 것은 libc.tmp_g4zlb.i.e. dirname 다음에 "tmp_" 다음에 5자리 임의 문자열이 오는 것처럼 보이는 각 디렉토리의 임시 복사본을 만드는 것입니다.

그래서 몇 가지 질문이 있습니다:

1) 이전 질문에서 논의한 것처럼 "x86-headers" 디렉토리를 반복하고 있습니다. 나는 아직도 여기서 find를 사용하고 있다. @Gilles가 지적했습니다.그의 대답이는 이상적이지 않습니다. 그가 옳을 수도 있습니다. 여기서 질문을 찾으세요:

a) 반환된 값은 와 유사합니다 ./libc. 나는 선두를 원하지 않는다 ./.

b) 내가 사용하고 있는 find 명령은 모든 디렉토리를 나열합니다. 에 대한 상대 경로가 포함된 경로만 고려하고 싶습니다 C/populate.sh.

Giles가 사용한 방법이 아마도 더 나을 것 같지만 이해가 되지 않습니다. 아래 목표를 참조하세요 gilles. 디렉토리 목록을 가져와서 배열에 저장하고 싶습니다.

2) 제가 겪고 있는 문제는 마지막 단계입니다.

echo "(progn (require 'parse-ffi) (ccl::parse-standard-ffi-files :$$i'.tmp_'$(RND)))" | \
/usr/lib/ccl-bootstrap/lx86cl -I /usr/lib/ccl-bootstrap/lx86cl.image; done \

libc.tmp_g4zlb관련된 점은 Common Lisp 컴파일러인 ccl에 임시 값을 전달하려고 한다는 것입니다 . 교체하지 않으면 다음과 같습니다.

echo "(progn (require 'parse-ffi) (ccl::parse-standard-ffi-files :libc.tmp_g4zlb))" | \
/usr/lib/ccl-bootstrap/lx86cl -I /usr/lib/ccl-bootstrap/lx86cl.image; done \

이것은 작동합니다. 위에 사용된 버전은 $$i그렇지 않습니다. 문제는 지배력 인 것 같습니다 ./. 그것 없이도 작동해야합니다. 기록상, 내가 얻는 오류는 다음과 같습니다.

? > Error: Too many arguments in call to #<Compiled-function CCL::PARSE-STANDARD-FFI-FILES #x488B8406>:
>        3 arguments provided, at most 2 accepted. 
> While executing: CCL::PARSE-STANDARD-FFI-FILES, in process listener(1).

./libc.tmp_g4zlb그러나 이것은 컴파일러에 전달할 때 발생하는 오류 가 아닙니다 . 오류는 다음과 같습니다

> Error: Filename "/home/faheem/test/foo/x86-headers/.\\/libc.tmp_g4zlb/C/**/" contains illegal character #\/
> While executing: CCL::%SPLIT-DIR, in process listener(1).

그래서 다른 일이 일어날 수도 있습니다.

3) 전반적인 접근 방식이 합리적으로 보입니까? 완전히 다른 전략이 포함되더라도 가능한 개선 사항을 자유롭게 제안해 주세요.

#!/usr/bin/make -f
# -*- makefile -*-

export SHELL=/bin/bash
export RND:=$(shell tr -cd a-z0-9 < /dev/urandom | head -c5)
export CCL_DEFAULT_DIRECTORY=$(CURDIR)

clean:
    rm -rf x86-headers/libc.tmp*

foo: clean
    PATH=$$PATH:$(CURDIR)/ffigen4/bin; \
    echo $$PATH; \
    export CURDIR=$(CURDIR); \
    echo $$CURDIR; \
    array=( $$(cd x86-headers && find . -mindepth 1 -maxdepth 1 -type d) ); \
    cd x86-headers && \
    for i in "$${array[@]}"; do \
    echo $$i; done; \
    for i in "$${array[@]}"; do \
    mkdir -p $$i."tmp_"$(RND)/C; done; \
    for i in "$${array[@]}"; do \
    cp -p $$i/C/populate.sh $$i".tmp_"$(RND)/C; done; \
    for i in "$${array[@]}"; do \
    cd $$i".tmp_"$(RND)/C; ./populate.sh; done; \
    for i in "$${array[@]}"; do \
    echo $$i'.tmp_'$(RND); done; \
    for i in "$${array[@]}"; do \
    echo "(progn (require 'parse-ffi) (ccl::parse-standard-ffi-files :$$i'.tmp_'$(RND)))" | \
    /usr/lib/ccl-bootstrap/lx86cl -I /usr/lib/ccl-bootstrap/lx86cl.image; done; \

gilles:
    cd x86-headers;
    for x in */C/populate.sh; do \
    echo -- "$${x%%/*}$$suffix"; done; \

업데이트: 이 질문(또는 질문)은 모든 세부 사항에서 길을 잃을 수 있습니다. 그래서 일을 단순화하려고 노력하겠습니다. 존재하다그의 대답, Giles는 다음과 같이 썼습니다.

for x in */C/populate.sh; do
  mkdir -- "${x%%/*}$suffix"
  mkdir -- "${x%%/*}$suffix/C"
  cp -p -- "$x" "./${x%%/*}$suffix/C"
done

그의 질문에 제가 댓글을 달았듯이, x여기서 형태의 패턴이 일치했습니다 */C/populate.sh. 또한 ${x%%/*}최상위 디렉터리 이름인 문자열의 첫 번째 부분과 일치합니다. 지금은

for x in */C/populate.sh; do                                                                                                                       
    myarr[] = "${x%%/*}"                                                                                                                    
done

내가 원하는 최상위 디렉토리 목록을 포함하는 배열을 생성합니다. 그러나 어떤 구문을 사용해야 할지 모르겠습니다. i=0, 1,...LHS의 인덱싱 처럼 루프에서 실행되는 카운터를 사용해야 합니다 . myarr이와 같은 코드가 작동한다면 문제가 어느 정도 해결될 것입니다.

답변1

루프의 배열에 무언가를 추가하려면 다음과 같이 사용할 수 있습니다.

for x in */C/populate.sh; do
  myarr=(${myarr[@]} "${x%%/*}")
done

카니발 시계정렬많은 일을 할 수 있는 문서입니다.

또는 +=배열에 추가를 사용할 수 있습니다(참조:여기) 이와 같이:

  myarr+=("${x%%/*}")

일부 의견:

내가 그의 질문에 대해 언급했듯이 여기서 x는 형식의 패턴과 일치합니다 */C/populate.sh.

나는 그것을 그렇게 설명하지 않을 것이다. */foo/bar글로벌 모드입니다. 이는 쉘에 의해 이 패턴과 일치하는 모든 파일/디렉토리 목록으로 확장됩니다. (시도해 보면 echo */C/populate.sh일치하는 항목이 모두 인쇄되는 것을 볼 수 있습니다.)
루프를 루프 변수로 사용하여 for이 일치 항목 집합을 반복합니다.$x

또한 ${x%%/*}최상위 디렉터리 이름인 문자열의 첫 번째 부분과 일치합니다.

${x%%/*}아무것도 "일치"하지 않습니다. $x인.프롬 입니다문서, 끝에서 ${var%%string}가장 긴 일치 항목을 제거합니다 . 이 경우 첫 번째 콘텐츠부터 모든 항목을 삭제하고 해당 콘텐츠를 "반환"(확장)합니다.string$var/

따라서 위의 세 줄의 코드를 분석하면 다음과 같은 일이 발생합니다.

  • 쉘은 glob 과 일치하는 항목(파일 또는 디렉토리) 목록을 생성합니다 */C/populate.sh.
  • 이들 각각에 대해 루프 본문은 $x해당 항목 세트로 실행 됩니다.
  • ${myarr[@]}배열의 각 항목 목록으로 확장
  • ${x%%/*}$x처음 부터 /모든 것을 빼고 확장
  • myarr그런 다음 기존 콘텐츠와 새롭고 간소화된 프로젝트를 사용하여 다시 빌드하세요.

관련 정보