Shell

使用 LS 命令列出目錄時的文件類型和取消引用

  • October 8, 2014

我正在嘗試將參數組合到ls命令以列出目錄內容。我基本上想要實現的是列出取消引用所有連結的目錄,但明確顯示列出的項目是一個連結。我嘗試組合--dereferenceand--classify選項,但我沒有顯示連結符號 ( @),*因為連結針對的是執行檔。

關於如何獲得這樣的結果的任何想法?我對ls命令以外的其他選擇持開放態度。

編輯: 我實際上使用了ls命令中的其他選項。我目前的命令及其選項如下:

ls -ogq -LB --group-directories-first --time-style=long-iso

我打算在我正在建構的應用程序中解析輸出,並且不能使用帶有箭頭 ( ->) 的預設連結輸出。目錄上的其他項目(例如文件夾和文件)也必須列出。

編輯(2):

澄清一下,我正在開發一個 Java 應用程序,它使用 SSH2 API 連接到伺服器並列出目錄。清單的結果然後用於使用 jsTree jQuery 外掛填充樹。目前我上面引用的命令給了我以下輸出:

felipe@simba:/mnt/drive$ ls -ogq --group-directories-first --time-style=long-iso 
total 12
drwxr-sr-x 2 4096 2014-06-11 18:04 folder1
drwxr-sr-x 6 4096 2014-06-27 19:35 folder2
dr-Sr-s-wt 2 4096 2014-06-27 13:51 folderWithPermissions
-rw-r--r-- 1    0 2014-06-30 10:42 file.txt
lrwxrwxrwx 1   49 2014-06-30 11:36 linkTeste -> folder2/dir/otherfile.txt

通過應用正則表達式,我可以通過查看權限來辨識什麼是文件夾、文件或連結。但是當我有一個連結時,我只需要列對外連結接名稱,而不是name -> destination. 如果我使用該命令的-L選項,則ls僅輸對外連結接名稱並且我獲得了引用目標的權限(這是一件好事),因為該-L選項取消引用該連結,但是這樣我就無法知道該連結實際上是關聯。

felipe@simba:/mnt/drive$ ls -ogq -L --group-directories-first --time-style=long-iso 
total 12
drwxr-sr-x 2 4096 2014-06-11 18:04 folder1
drwxr-sr-x 6 4096 2014-06-27 19:35 folder2
dr-Sr-s-wt 2 4096 2014-06-27 13:51 folderWithPermissions
-rw-r--r-- 1    0 2014-06-30 10:42 file.txt
-rwxr-xr-x 1    0 2014-06-27 18:40 linkTeste

我只需要列對外連結接名稱,知道它是一個連結並知道目標是什麼(文件、文件夾或連結)。我可以處理不同類型的輸出,因為無論如何我都要應用正則表達式。

也歡迎使用findor的替代方案。stat

編輯以響應更新的問題

由於您只關心連結、目錄和正常文件,並且不需要處理ls可以辨識的其他文件類型(FIFO、套接字等),因此您可以執行類似stat. 對於以下範例,我創建了以下測試環境:

$ ls -l
total 4.0K
-rw-r--r-- 1 terdon terdon    0 Jun 30 23:12 a new?line 
-rw-r--r-- 1 terdon terdon    0 Jun 30 23:12 a space
-rw-r--r-- 1 terdon terdon    0 Jun 30 23:12 a?tab
drwxr-xr-x 2 terdon terdon 4.0K Jun 30 23:11 dir1
lrwxrwxrwx 1 terdon terdon    4 Jun 30 23:13 linktodir1 -> dir1
lrwxrwxrwx 1 terdon terdon    7 Jun 30 23:13 sh -> /bin/sh

如您所見,這些包括連結、執行檔的連結、帶空格的文件名、帶製表符 ( \t) 的文件名和帶換行符 ( \n) 的文件名。這些文件中的大多數會破壞您的ls方法,但stat可以正確處理它們:

$ stat --printf "%A\t%N\t%F\n" * 
-rw-r--r--  ‘a new\nline’   regular file
-rw-r--r--  ‘a space’   regular file
-rw-r--r--  ‘a\ttab’    regular file
drwxr-xr-x  ‘dir1’  directory
lrwxrwxrwx  ‘linktodir1’ -> ‘dir1’  symbolic link
lrwxrwxrwx  ‘sh’ -> ‘/bin/sh’   symbolic link

的相關部分man stat

–printf=格式

像 –format,但解釋反斜杠轉義,並且不輸出強制性的尾隨換行符。如果你想要換行符,請在 FORMAT 中包含 \n

%A 人類可讀形式的訪問權限

%F 文件類型

%N 引用的文件名,如果是符號連結,則取消引用

請注意,欄位由 分隔\t,這意味著您將能夠優雅地處理欄位中的空格(例如在文件名中)。

你提到你不能處理->。我不完全確定為什麼,但是您可以將其刪除sed

$ stat --printf "%A\t%N\t%F\n" * | sed 's/->//' 
lrwxrwxrwx  ‘linktodir1’  ‘dir1’    symbolic link

或用另一個字元串替換它:

$ stat --printf "%A\t%N\t%F\n" * | sed 's/->/→/' | grep linktodir
lrwxrwxrwx  ‘linktodir1’ → ‘dir1’   symbolic link

或者只是解析文件類型。


根據您要執行的操作,將您正在搜尋的三種文件類型中的每一種分開並分別處理可能會很有用。如果是這樣,請使用find1及其-printf選項:

$ find ./ -maxdepth 1 -mindepth 1 -type f -printf '%M\t%P\t%l\n'  ## files
$ find ./ -maxdepth 1 -mindepth 1 -type d -printf '%M\t%P\t%l\n'  ## directories
$ find ./ -maxdepth 1 -mindepth 1 -type l -printf '%M\t%P\t%l\n'  ## links

在這種情況下,printf指令是

         %M     File's permissions (in symbolic form, as for  ls).   This
                directive is supported in findutils 4.2.5 and later.
         %P     File's  name  with  the name of the command line argument
                under which it was found removed.
         %l     Object of symbolic link (empty string if file  is  not  a
                symbolic link).

您還可以將上述內容組合成一個命令(使用find-o運算符),但它允許您-printf根據文件類型列印任意字元串。例如:

$ find ./ -maxdepth 1 -mindepth 1 \( -type l -printf 'link:\t%M\t%P\t%l\n' \) \
-o \( -type d -printf 'dir:\t%M\t%P\n' \) \
-o \( -type f -printf 'file:\t%M\t%P\n' \) 
file:   -rw-r--r--  a?tab
file:   -rw-r--r--  a space
link:   lrwxrwxrwx  linktodir1  dir1
file:   -rw-r--r--  a new?line
dir:    drwxr-xr-x  dir1
link:   lrwxrwxrwx  sh  /bin/sh

如果它的輸出未顯示在終端上,上面的命令將正確\t解釋。\n但是,要正確處理帶有換行符的文件名,您在解析時需要小心(確保“行”以 開頭[file|dir|link]:)或\0在每次呼叫中用作行終止符printf而不是\n

$ find ./ -maxdepth 1 -mindepth 1 \( -type l -printf 'link:\t%M\t%P\t%l\0' \) \
-o \( -type d -printf 'dir:\t%M\t%P\0' \) \
-o \( -type f -printf 'file:\t%M\t%P\0' \)

1 -maxdepth並且-mindepth是 GNU 擴展,因此這種方法僅適用於 GNU find


以下是針對該問題的第一個不太具體的版本的解決方案發布的。我將它們留在這裡,因為它們可能對其他人有用。

  1. 殼牌和readlink
for f in *; do 
readlink "$f" >/dev/null && echo "$(readlink -f "$f") (link)" || echo "$f";
done

範例輸出:

/etc (link)
foo
sample.R
sample.R~

上面遍歷目前一個下的所有文件和目錄,如果readlink返回成功(如果$f是連結),它將取消引用它(readlink -f,注意這將跟隨所有連結。如果您只想要第一級,請刪除-f)並列印目標與(link)。如果不是,它只會列印$f。 2. 如果這僅適合您並且不打算被解析,請使用ls -l

$ ls -l
total 512116
-rw-r--r-- 1 terdon terdon    100641 Jun 30 19:10 er
lrwxrwxrwx 1 terdon terdon         5 Jun 30 19:12 etc -> /etc/
-rw-r--r-- 1 terdon terdon 524288000 Jun 30 19:10 foo
-rwxr--r-- 1 terdon terdon       353 Jun 30 15:22 sample.R
-rwxr--r-- 1 terdon terdon       249 Jun 30 14:51 sample.R~

這將清楚地表明與link -> target.

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