從 bash 路徑數組中提取缺失的路徑
我有一組路徑:
paths=( /foo/exists1 /foo/exists2 /foo/missing1 )
要找到那些失去的:
ls "${paths[@]}" 1>/dev/null
顯示:
ls: 無法訪問’/foo/missing1’: 沒有這樣的文件或目錄
好的。現在我想清理它:
ls "${paths[@]}" 1>/dev/null | sed 's/ls: cannot access //' | sed 's/: No such file or directory//''
但我得到:
ls: 無法訪問 ‘/foo/missing1’: 沒有這樣的文件或目錄
/foo/exists1
/foo/exists2
所以
sed
不起作用,並且現有文件也會顯示。為什麼會發生這種情況(為什麼會忽略
1>/dev/null
),我該如何解決?
您已經發現了您的程式碼沒有按照您的預期執行的直接原因:錯誤
ls
被報告給 stderr(如POSIX 所建議的那樣),該錯誤未被管道擷取為輸入。因此,您得到了正常輸出(通過您的sed
語句未更改通過)和 stderr(繞過它們)的混合。我不知道為什麼您的ls
輸出在兩次通話之間發生了變化;將標準輸出重定向到 /dev/null 應該具有從輸出中刪除所有“正常”(現有路徑)的效果。不過,解決此問題的方法不是將 stderr 推入 stdout。
ls
如果您想要一個可靠的腳本,那麼對輸出進行後處理是一個危險的想法。關於該主題的一篇好文章是“為什麼不應該解析 ls(1) 的輸出”,可在 woodedge.org 站點上找到。Unix 和 Linux 網站上的一個深入 Q/A 涉及一些問題:為什麼不解析ls
(以及要做什麼)?. 結果是 UNIX 文件名可以包含幾乎任何字元,包括空格、製表符、換行符、單引號、雙引號、轉義單引號等!對於一些簡單的例子,考慮這些名稱的目錄,所有這些都是完全合法的:
- “沒有這樣的文件” (
mkdir "No such file"
)- “ls: 無法訪問 ‘foo’: 沒有這樣的文件或目錄” (
mkdir "ls: cannot access 'foo': No such file or directory"
)- “目錄
和
嵌入式
換行符” (
mkdir $'directory\nwith\nembedded\newlines'
)第一個是被
grep
. 第二個也被錯誤地擷取,但隨後進一步被破壞成一條完全不同的路徑——可能存在也可能不存在!——通過sed
陳述。第三個是當你將輸出傳遞給ls
面向行的程序時發生的一個例子;如果該目錄不存在,ls
將在不止一行上這樣說,這可能就是您最終得到兩個單獨sed
語句的方式!為了區分“好路徑”(存在且可讀的路徑)和“壞路徑”,我建議循環遍歷數組並為每個數組建構新數組。
for p in "${paths[@]}" do if [ -r "$p" ] then goodpaths+=("$p") else badpaths+=("$p") fi done
然後你可以對每組做任何你喜歡的事情:
printf 'Good path: -->%s<--\n' "${goodpaths[@]}" echo printf 'Bad path: -->%s<--\n' "${badpaths[@]}"