Bash

循環遍歷 bash 中的目錄條目並保存到數組

  • August 4, 2012

(請參閱問題底部的更新)。

這是“使用 find 製作目錄副本”的後續問題。

這個問題涉及操作一堆目錄,這太複雜了,無法在單個命令中處理,所以我決定採用將目錄列表保存到 bash 數組的方法,儘管對可移植性有所保留。似乎 POSIX shell 標準(我理解的 Unix shell 標準)沒有數組。

我正在使用的 makefile 出現在下面。除了最後一步之外,這有效。下面是我正在嘗試做的事情的總結。

正如前面問題中所討論的,我想遍歷目錄,並將包含該文件(但也可能包含其他文件)x86-headers的頂級子目錄的列表收集到一個 bash 數組中。C/populate.sh例如,在我的測試設置中,只有一個目錄x86-headers包含該文件libc/C/populate.sh,即 libc.

然後我對這些子目錄執行一些操作。其中最重要的是我為每個目錄製作了一個臨時副本,看起來像libc.tmp_g4zlb. 即 dirname 後跟 ’tmp_’ 後跟 5 位隨機字元串。

所以,一些問題:

  1. 正如前面問題中所討論的,我正在遍歷目錄“x86-headers”。在這裡我仍然使用find。@Gilles 在他的回答中表示這並不理想。他可能是對的。在此處查找的問題:

a)返回的值看起來像./libc。我不想領先 ./

b) 我使用的 find 命令列出了所有目錄。我只想考慮那些包含相對路徑為 C/populate.sh.

Gilles 使用的方法可能更好,但我不明白。請參閱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給 ccl,它是一個 Common Lisp 編譯器。沒有替換,它看起來像

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

更新:問題(或問題)可能在所有細節中都失去了。所以,讓我試著簡化一下。吉爾斯在他的回答中寫道

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

將創建一個包含頂級目錄列表的數組,這就是我想要的。但是,我不知道使用什麼語法。我需要使用一個在循環上執行的計數器,比如在 LHS 上i=0, 1,...建立索引。myarr如果我有這樣的工作程式碼,它將在某種程度上解決我的問題。

如果您想在循環中將內容附加到數組中,可以使用以下內容:

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

請參閱 bash數組文件,了解您可以使用它們做的許多事情。

或者,您可以像這樣使用+=附加到數組(參見此處):

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

幾點評論:

正如我對他的問題的評論,這裡的 x 匹配表單的模式*/C/populate.sh

我不是這樣解釋的。*/foo/bar是一個全域模式。它由 shell 擴展為與此模式匹配的所有文件/目錄的列表。(試試看echo */C/populate.sh,你會看到列印的所有匹配項。)

循環for迭代這組匹配項,使用$x循環變數。

此外,${x%%/*}匹配字元串的第一部分,即頂級目錄名稱。

${x%%/*}不“匹配”任何東西。這是一個字元串操作函式,在$x. 從docs${var%%string}中,string$var. 在這種情況下,它會從一開始就刪除所有內容/並“返回”(擴展到)那個。

所以要分解上面的三行程式碼,會發生什麼:

  • shell 生成與 glob 匹配的項目(文件或目錄)列表*/C/populate.sh
  • 對於其中的每一個,循環體都是在$x設置為該項目的情況下執行的
  • ${myarr[@]}展開到數組中每個項目的列表
  • ${x%%/*}從一開始就擴展為$x減去所有內容/
  • myarr然後用它的舊內容加上新的、精簡的項目來重建。

引用自:https://unix.stackexchange.com/questions/44554