循環遍歷 bash 中的目錄條目並保存到數組
(請參閱問題底部的更新)。
這是“使用 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 位隨機字元串。所以,一些問題:
- 正如前面問題中所討論的,我正在遍歷目錄“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
然後用它的舊內容加上新的、精簡的項目來重建。