我的目錄中有n
很多檔案../in/
。我希望從這些文件中處理最舊的文件並將其發送到../complete/
目錄。其余文件將發送到該../error/
目錄。有人可以幫忙嗎?
答案1
要將最舊的文件複製到../complete
:
cp -v "$(find ../in -maxdepth 1 -type f -printf '%T@ %p\0' | sort -zn | \
sed -zn '1s/[0-9,\.]\+ //p')" ../complete
要將除最舊的之外的所有內容複製到../error
:
find ../in -maxdepth 1 -type f -printf '%T@ %p\0' | sort -zn | \
sed -zn '2,$s/[0-9,\.]\+ //p' | xargs -0 cp -vt ../error
解釋:
find
-maxdepth 1
僅下降1級;因此它不會重複搜尋目錄。-type f
僅匹配文件。-printf '...'
自訂輸出格式。%T@
給出文件的最後修改時間(時間戳記),%p
是文件的名稱。注意\0
最後。檔案以空字節分隔列印,而不是換行分隔,因為換行可能是檔案名稱中的字符,這會破壞命令。
sort -zn
這將讀取以空位元組分隔 ( ) 的輸出-z
並按數字排序 (-n
)。sed -zn
讀取以空位元組分隔的輸出。1
將僅匹配第一行(第一個命令)並將2,$
匹配所有其他行(第二個命令)s/[0-9,\.]\+ //p
將從輸出中刪除前導時間戳記。
- 僅從第二個命令:
xargs -0 cp -vt ../error
處理以空位元組分隔 ( ) 的輸出-0
並呼叫cp -vt ../error
所有輸入,這會複製檔案。
輸出範例:
$ ls -lt ../in/
total 0
-rw-r--r-- 1 user user 0 Jun 24 08:18 file2
-rw-r--r-- 1 user user 0 Jun 24 08:18 file3
-rw-r--r-- 1 user user 0 Jun 24 08:18 file4
-rw-r--r-- 1 user user 0 Jun 24 08:18 file5
-rw-r--r-- 1 user user 0 Jun 24 08:17 file_oldest
$ cp -v "$(...)" ../complete
'../in/file_oldest' -> '../complete/file_oldest'
$
$ find ... | xargs ... ../error
'../in/file2' -> '../error/file2'
'../in/file3' -> '../error/file3'
'../in/file4' -> '../error/file4'
'../in/file5' -> '../error/file5'
答案2
若要尋找最舊的檔案並將其移至所需的目錄,請使用:
# cd to ../in/
$ ls -lt | grep -v '^d' | tail -1 | awk '{print $NF}' | xargs -I '{}' mv '{}' ../complete/
現在最舊的文件已移出,您可以將所有文件移至../error/
$ mv -- * ../error/
如果您有任何以--
.mv
-
答案3
建立在拉胡爾的回答:
$ ls -ltr | grep -v '^d' | awk 'NR==2 {print $NF; exit}' | xargs -I '{}' mv -- '{}' ../complete/
筆記:
- 你說你想對「最舊的文件」做一些事情。所有答案都假設您的意思是最近最少修改。如果你的意思是最近改變了, 這樣說的;答案會略有不同。如果你的意思是最近已創建,你想要的在Unix中幾乎是不可能的。
ls -lt
(拉胡爾使用的)按修改日期/時間的順序以長格式列出當前目錄,最新的在前,最舊的在後。ls -ltr
是個r與此相反;最舊的排在最前面,最新的排在最後。- 如果您可能有名稱以句點 (
.
),將A
選項加入ls
;例如,ls -ltrA
。 (選項的順序並不重要;您可以使用ls -ltAr
、ls -lAtr
、 或者,ls -ltr -A
即使您願意。) - 我撒了謊。
ls
目錄的長列表總是total
先有一行。在 中ls -ltr
,最舊的條目位於第二線。 grep -v '^d'
過濾掉目錄(如果有)。awk 'NR==2 { print $NF; exit }'
列印第二行(最舊的文件)的最後一個欄位(檔案名稱*),然後退出。- 這比 少了一個進程
tail -1 | awk '{print $NF}'
。 - 這可能會工作得更快,因為當
awk
退出時,ls
也可能退出,並且您將避免產生整個目錄的清單。 grep
你可以透過這樣做來消除ls -ltr | awk '! /^d/ { count++ } count==2 { print $NF; exit }'
但我不建議這樣做。過於複雜的腳本很難維護。
- 這比 少了一個進程
- 之後
--
的mv
在xargs
命令中如果您有任何以 a 開頭的檔案名,則這是必需的-
。 你其實並不需要
xargs
.您可以將上面的命令簡化為$ mv -- $(ls -ltr | grep -v '^d' | awk 'NR==2 { print $NF; exit }') ../complete/
________
* 就像拉胡爾的答案一樣,如果檔案名稱包含空格或製表符,這將會失敗 - 如果檔案名稱包含換行符,情況會更糟。
如果您可能有名稱以句點 (.
),shopt -s dotglob
在做之前做
$ mv -- * ../error/