Find

在另一個目錄中遞歸地“查找”包含字元串和符號連結文件的文件名

  • August 8, 2019

我正在嘗試對我正在處理的項目中的一組特定文件進行符號連結。

我希望符號連結的每個文件名中都有一個已知字元串。

這是我到目前為止所擁有的:

ln -s find ~/path/to/src/ -name "*stringtomatch*" find ~/path/to/dest

我在目標中設置了目錄結構以匹配源,但它只是目錄,所以如果為空目標編寫命令更容易,我不介意刪除這些。

更新:

我現在已經接受了一個可行的答案,我想分享一些上下文,以便類似的案例可以更容易地找到解決方案。

我在 Netbeans 中執行大部分編碼。當我為一個項目建構包時,我傾向於命名所有關聯的文件,以便它們具有共同的部分文件名。這使我可以在項目中移動時輕鬆找到自己的封包件。但是,在我目前的項目中,由於涉及大量文件和目錄,這非常耗時。

我現在擁有的是為我自己的每個包定義的單獨項目,它只顯示該包的文件,同時保持主項目層次結構。

通過在主項目中建構使用符號連結到我的封包件的單獨包項目,我有效地創建了我認為是完美的解決方案,在目前形式的 Netbeans IDE 中似乎沒有可用的解決方案。

每個子項目只允許我處理僅與自身相關的文件子集,這確實使我在鍵盤上的時間更有效率。

我相信 Eclipse 內置了這個功能,雖然我沒有 Eclipse。

因此,儘管是一種妥協,但我相信 Netbeans 的這種解決方法與我今天可以實現的一樣乾淨。這是一個巨大的好處,它也能正常工作,如果不是比我預期的更好的話。

我曾期望在編輯子項目後手動執行主同步。情況並非如此,主站仍然保持自動同步。

我創建了一個簡短的腳本來執行此操作,輸出很好,應該很容易檢查結果。它不需要創建目標目錄結構。使用如下:

$ ./recursive-symlink.sh --help
Usage:
 ./recursive-symlink.sh <source_path> <dest_path> <find_args...>

為了顯示它的用法,假設我在開始時有以下文件/目錄:

├── recursive-symlink.sh*
└── src/
   ├── dir1/
   │   ├── file_A_misc.txt
   │   └── file_B_sub.txt
   ├── dir3/
   │   ├── file_A3.txt
   │   ├── file_C.txt
   │   └── subsub_dir/
   │       ├── file_Asubsub.txt
   │       └── file_D.txt
   ├── dir_A/
   │   └── should_be_empty.dat
   ├── file_A.txt
   └── file_B.txt

如果我執行:

$ find -name '*_A*'
./src/file_A.txt
./src/dir3/file_A3.txt
./src/dir3/subsub_dir/file_Asubsub.txt
./src/dir_A
./src/dir1/file_A_misc.txt

我可以看到哪些文件將被連結。然後我像這樣執行腳本:

$ ./recursive-symlink.sh src/ dest/ -name '*_A*'
src/file_A.txt
mkdir: created directory 'dest'
'dest/file_A.txt' -> '../src/file_A.txt'

src/dir3/file_A3.txt
mkdir: created directory 'dest/dir3'
'dest/dir3/file_A3.txt' -> '../../src/dir3/file_A3.txt'

src/dir3/subsub_dir/file_Asubsub.txt
mkdir: created directory 'dest/dir3/subsub_dir'
'dest/dir3/subsub_dir/file_Asubsub.txt' -> '../../../src/dir3/subsub_dir/file_Asubsub.txt'

src/dir_A
'dest/dir_A' -> '../src/dir_A'

src/dir1/file_A_misc.txt
mkdir: created directory 'dest/dir1'
'dest/dir1/file_A_misc.txt' -> '../../src/dir1/file_A_misc.txt'

我的最終狀態將是:

├── recursive-symlink.sh*
├── src/
│   ├── dir1/
│   │   ├── file_A_misc.txt
│   │   └── file_B_sub.txt
│   ├── dir3/
│   │   ├── file_A3.txt
│   │   ├── file_C.txt
│   │   └── subsub_dir/
│   │       ├── file_Asubsub.txt
│   │       └── file_D.txt
│   ├── dir_A/
│   │   └── should_be_empty.dat
│   ├── file_A.txt
│   └── file_B.txt
└── dest/
    ├── dir1/
    │   └── file_A_misc.txt -> ../../src/dir1/file_A_misc.txt
    ├── dir3/
    │   ├── file_A3.txt -> ../../src/dir3/file_A3.txt
    │   └── subsub_dir/
    │       └── file_Asubsub.txt -> ../../../src/dir3/subsub_dir/file_Asubsub.txt
    ├── dir_A -> ../src/dir_A/
    └── file_A.txt -> ../src/file_A.txt

您可以看到該dest目錄以及所有遞歸子目錄都是自動創建的,並且在該dest目錄上,只有與該*_A*模式匹配的文件被連結。


這裡的腳本原始碼:

#!/bin/bash

verbose='-v'  # you may comment this line

if [ "$1" == '-h' ] || [ "$1" == '--help' ] || [ $# -lt 3 ]
then
   echo "Usage:"
   echo "  $0 <source_path> <dest_path> <find_args...>"
   exit
fi

src="${1%/}" ; shift
dest="${1%/}" ; shift
relflag='' ; [ "${src:0:1}" != '/' ] && relflag='-r'

find "$src" \( "$@" \) -print0 |
   while IFS= read -r -d '' f
   do
       base_fname="${f#$src}"
       [ "$verbose" ] && echo "${f}"
       dest_ln="$dest/${base_fname#/}"
       dest_dir="$(dirname "$dest_ln")"
       mkdir -p $verbose "$dest_dir"
       ln $relflag -s $verbose -t "$dest_dir" "$f"
       [ "$verbose" ] && echo
   done

如果您已經在目標位置創建了必要的目錄,那麼使用findand的 GNU 實現xargs並不難:

find ~/path/to/src -name "*stringtomatch*" -printf "%P\0" |
 xargs -r0 --replace ln -s ~/path/to/src/'{}' ~/path/to/dest/'{}'

輸出刪除了源目錄參數的-printf "%P\0"路徑,並以空字節結尾。

xargs然後讀取find輸出。

-0表示要使用的參數是空分隔的。

--replace告訴 xargs{}用參數替換(也意味著每個參數執行一個命令)。

最後給出了替換參數的命令。

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