Bashでディレクトリエントリを繰り返して配列に保存する

Bashでディレクトリエントリを繰り返して配列に保存する

(質問の一番下の更新を参照してください)。

フォローアップの質問です「ディレクトリのコピーを作成するには、検索を使用してください。」

問題は、単一のコマンドで処理するには複雑すぎる複数のディレクトリを操作することに関連していたので、移植性のいくつかの留保がありますが、ディレクトリリストをbash配列に保存する方法を決定しました。 POSIXシェル標準(私が知る限りUnixシェル標準)には配列がないようです。

私が使用するmakefileは次のようになります。これは最後のステップを除いて機能します。私がやろうとしていることの概要は次のとおりです。

前の質問で説明したように、ディレクトリを繰り返しながら、ファイルをx86-headers含む最上位のサブディレクトリのリストをbash配列として収集したいと思います(他のファイルも含めることができます)。たとえば、私のテスト設定にはファイルを含むディレクトリ C/populate.shが1つしかありません。x86-headerslibc/C/populate.shlibc

次に、これらのサブディレクトリに対していくつかのタスクを実行します。これらの最も重要なことは、libc.tmp_g4zlb.ie 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/

したがって、上記の3行のコードを分析すると、次のことが起こります。

  • シェルは、globと一致する項目(ファイルまたはディレクトリ)のリストを生成します*/C/populate.sh
  • これらのそれぞれについて、ループ本文は対応する$x項目のセットとして実行されます。
  • ${myarr[@]}配列内の各項目のリストに展開
  • ${x%%/*}$x最初から/すべてを除いて拡張
  • myarrその後、既存のコンテンツと新しく合理化されたプロジェクトを使用して再構築します。

おすすめ記事