當使用帶有 glob *.{a,b,}test 的大括號擴展時,忽略 zsh 中的“無匹配項”

當使用帶有 glob *.{a,b,}test 的大括號擴展時,忽略 zsh 中的“無匹配項”

我想列出foldername名為 或 . 的test資料atest夾中的所有檔案btest

我的第一個反應就是跑ls ./foldername/*.{a,b,}test

這工作正常,除非擴展名沒有任何內容atest,在這種情況下我會收到錯誤zsh: no matches found: ./foldername/*.atest

有什麼方法可以簡單地忽略此錯誤並列印確實存在的文件嗎?

我需要它在 zsh 和 Bash 中都能工作。

答案1

ls -d ./foldername/*.{a,b,}test

{a,b,...}不是全域運算符,這是大括號擴展,首先擴展為:

ls -d ./foldername/*.atest ./foldername/*.btest ./foldername/*.test

每個 glob 都會單獨擴展,如果任何 glob 不匹配,則該命令將按照您的預期被取消zsh(或fish; 在 中bash,您需要failglob獲得類似行為的選項)。

在這裡,您希望使用與所有這些檔案相符的單一 glob,並且僅在該 glob 與任何檔案都不匹配時才取消命令:

ls -d ./foldername/*.(a|b|)test

您不想使用nullglob,就好像沒有一個 glob 匹配一樣,它將在ls沒有參數的情況下運行,因此列出當前目錄。cshnullglob在這方面更好,因為它刪除了不匹配的 glob,但如果所有 glob 都無法匹配,則仍然會取消命令。

您不會想使用nonomatch,因為這會給您帶來破壞行為,bash這將是一種恥辱。

對於同時適用於 和 的 glob 替代方案zshbash您可以使用 ksh glob(set -o kshglobinzshshopt -s extglobin bash)。

然後,你會這樣做:

ls -d ./foldername/*.@(a|b|)test

或者:

ls -d ./foldername/*.?([ab])test

新增該failglob選項bash以避免 glob 在ls不匹配時逐字傳遞。

為什麼 nullglob 不是預設值?了解更多。

答案2

最好這樣做find

find ./foldername -maxdepth 1 -name '*.atest' -o -name '*.btest' -o -name '*.test'

答案3

我遇到了這個問題,首先透過破解 ls 本身來解決它。完成後,我意識到我所需要的只是簡單的 C 程式:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

int main(int argc, char* argv[]) {
  struct stat statbuf;
  int i;
  for( i=1; i<argc; i++ ) {
    if( stat(argv[i],&statbuf) == 0 ) {
      printf("%s\n",argv[i]);
    }
  }
}

所有這一切以及它需要做的就是運行其命令列參數並回顯與有效文件相對應的那些字串(即 stat() 成功的文件)。

當然,我們可以使用同樣簡單的 Python、Perl 甚至運行 stat 的 shell 函數來模擬它,但用 C 編寫它可以使其運行速度更快。

至於 hacking ls,我已經在我的個人 wiki 上進行了運行:http://linux.chalisque.net/LsIgnoreMissing

答案4

@DopeGhoti 的評論對我有用。

即,將錯誤重定向到/dev/null使用2>運算符,如下所示:

ls ./foldername/*.{a,b,}test 2> /dev/null

相關內容