Journey of a noob

Learn From Noobs

以例子解釋 ‘find -exec’ 與 ‘find -execdir’ 的不同

Posted at # Unix/Linux

以例子解釋 ‘find -exec’ 與 ‘find -execdir’ 的不同

find -exec 是一個很常用的指令,但有些人並不知道 find -execdir 這個指令的存在以及它們的分別,在這篇文章中,我們會探討這兩個指令的分別。

1. ‘find -exec’ 跟 ‘find -execdir’ 在不同的位置執行

find -exec 會在起始的位置執行,而 find -execdir 則會在目標存在的位置執行。

指令執行位置
find -exec起始的位置
find -execdir目標存在的位置

讓我們用例子解說一下吧。

  1. 創建以下的檔案架構。

    noob@learnfromnoobs:~$ tree find-test/
    find-test/
    ├── dir1
       └── myfile1
    └── dir2
        └── myfile2
    
    2 directories, 2 files
    

    我們可以用以下的指令創建上述檔案架構。

    $ mkdir find-test
    $ mkdir find-test/dir1
    $ mkdir find-test/dir2
    $ touch find-test/dir1/myfile1
    $ touch find-test/dir2/myfile2
    
  2. 在 find-test 下執行 find -exec

    noob@learnfromnoobs:~/find-test$ find . -name 'myfile*' -exec ls -l \;
    total 8
    drwxrwxr-x 2 noob noob 4096 Jan 27 09:55 dir1
    drwxrwxr-x 2 noob noob 4096 Jan 27 09:55 dir2
    total 8
    drwxrwxr-x 2 noob noob 4096 Jan 27 09:55 dir1
    drwxrwxr-x 2 noob noob 4096 Jan 27 09:55 dir2
    

    find 指令成功找到 ‘myfile1’ 和 ‘myfile2’,由於 find 指令指到 2 個結果,find 指令會為每個結果在起始的位置(find-test)各自執行 1 次 ls,所以我們會看到 find-test 下的 ls 結果 2 次。

  3. 在 find-test 下執行 find -execdir

    noob@learnfromnoobs:~/find-test$ find . -name 'myfile*' -execdir ls -l \;
    total 0
    -rw-rw-r-- 1 noob noob 0 Jan 27 09:55 myfile1
    total 0
    -rw-rw-r-- 1 noob noob 0 Jan 27 09:55 myfile2
    

    因為我們正在目標存在的位置(dir1 及 dir2)執行 ls,所以我們會看到在 dir1 及 dir2 下的 ls 結果。

    如果想知道更多,請參閱 find 指令的 man page。

  4. 如果你對上述的結果仍然抱有懷疑,你可以使用 echo 檢查一下符合 find 條件的目標。

    noob@learnfromnoobs:~/find-test$ find . -name 'myfile*' -exec echo {} \;
    ./dir1/myfile1
    ./dir2/myfile2
    noob@learnfromnoobs:~/find-test$ find . -name 'myfile*' -execdir echo {} \;
    ./myfile1
    ./myfile2
    

    我們可以看到,對於 find -exec 指令來說,當前的位置(.)是 ~/find-test,而對於 find -execdir 指令來說,當前的位置則是 ~/find-test/dir1 和 ~/find-test/dir2,亦即是目標 myfile1 和 myfile2 存在的位置。

注意

在執行指令前,我們可以使用 -ls 來檢查一下符合 find 條件的目標,確保我們真是在正確的檔案上執行指令,你永遠不會想意外地刪除了任何檔案。

noob@learnfromnoobs:~/find-test$ find . -name 'myfile*' -ls;
   524517      0 -rw-rw-r--   1 noob     noob            0 Jan 27 09:55 ./dir1/myfile1
   524518      0 -rw-rw-r--   1 noob     noob            0 Jan 27 09:55 ./dir2/myfile2

2. ‘find -execdir’ 不允許 ’.’ 出現在 $PATH 環境變數(Environment Variable)

根據 find 指令的 man page,

If you use this option, you must ensure that your $PATH environment variable does not reference `.’; otherwise, an attacker can run any commands they like by leaving an appropriately-named file in a directory in which you will run -execdir.

當使用 find -execdir 時,PATH環境變數中是不能夠出.的。(有些人喜歡在PATH 環境變數中是不能夠出現 '.' 的。(有些人喜歡在 PATH 環境變數中加入 ’.’,這樣他們在當前位置執行程式時就不用在前面輸入 ‘./‘,筆者強烈不建議這樣做,如果你想知道更多,可以參這篇文章

純粹因為實驗目的,我們可以在我們的 $PATH 環境變數中暫時加入 ’.’,看看 find -execdir 會有何回應。

  1. 在 $PATH 環境變數中加入 ’.’。

    noob@learnfromnoobs:~/find-test$ export PATH=$PATH:.
    noob@learnfromnoobs:~/find-test$ echo $PATH
    /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:.
    
  2. 看看 find -exec 會否不滿。

    noob@learnfromnoobs:~/find-test$ find . -name 'myfile*' -exec ls -l \;
    total 8
    drwxrwxr-x 2 noob noob 4096 Jan 27 09:55 dir1
    drwxrwxr-x 2 noob noob 4096 Jan 27 09:55 dir2
    total 8
    drwxrwxr-x 2 noob noob 4096 Jan 27 09:55 dir1
    drwxrwxr-x 2 noob noob 4096 Jan 27 09:55 dir2
    

    指令順利執行了,find -exec 不介意 ’.’ 出現在 $PATH 環境變數。

  3. 看看 find -execdir 會否不滿。

    noob@learnfromnoobs:~/find-test$ find . -name 'myfile*' -execdir ls -l \;
    find: The current directory is included in the PATH environment variable, which is insecure in combination with the -execdir action of find.  Please remove the current directory from your $PATH (that is, remove ".", doubled colons, or leading or trailing colons)
    

    噢喔!很明顯,find -execdir 不喜歡 $PATH 環境變數中存在 ’.’,指令無法執行。


總結

總結來說,find -execfind -execdir 之間有 2 個分別:

  1. find -exec 會在起始的位置執行,而 find -execdir 則會在目標存在的位置執行。
  2. find -execdir 不允許 ’.’ 出現在 $PATH 環境變數。

我希望你喜歡這篇文章,並從中得到了新知識。

記得要不斷學習,have fun!