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,$
他のすべて(2番目のコマンド)に一致します。s/[0-9,\.]\+ //p
出力から先頭のタイムスタンプを削除します。
- 2 番目のコマンドのみ:
xargs -0 cp -vt ../error
出力の null バイト区切り (-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/
で始まるファイル名やディレクトリ名がある場合、after--
が必要です。mv
-
答え3
構築するラフルの答え:
$ ls -ltr | grep -v '^d' | awk 'NR==2 {print $NF; exit}' | xargs -I '{}' mv -- '{}' ../complete/
ノート:
- 「最も古いファイル」で何かしたいとおっしゃっています。すべての回答は、最も最近変更されたファイルという意味だと想定しています。最も最近変更されたファイルという意味ならかわったと言えば答えは若干異なります。作成したあなたが望むことは Unix ではほとんど不可能です。
ls -lt
(Rahulが使用した方法)現在のディレクトリを長い形式で、変更日時順に、新しい順に、古い順にリストしますls -ltr
。rその逆で、一番古いものが最初で、一番新しいものが最後になります。- 名前がピリオド(
.
) の場合は、A
にオプションを追加しますls
。例:ls -ltrA
。(オプションの順序は重要ではありません。必要に応じてls -ltAr
、ls -lAtr
、 も使用できます。)ls -ltr -A
ls
嘘をつきました。ディレクトリの長いリストは常にtotal
最初の行にあります。ではls -ltr
、最も古いエントリは2番ライン。grep -v '^d'
ディレクトリ(存在する場合)を除外します。awk 'NR==2 { print $NF; exit }'
2 行目 (最も古いファイル) の最後のフィールド (ファイル名*) を出力し、終了します。- これは よりも 1 つ少ないプロセスです
tail -1 | awk '{print $NF}'
。 - この方法は、 が
awk
終了するとls
も終了する可能性があり、ディレクトリ全体のリスト生成を回避できるため、より高速に動作する可能性があります。 これ
grep
を行うことで、ls -ltr | awk '! /^d/ { count++ } count==2 { print $NF; exit }'
しかし、私はそれをお勧めしません。過度に複雑なスクリプトは保守が困難です。
- これは よりも 1 つ少ないプロセスです
- 後
--
mv
xargs
コマンドでファイル名が-
。 は実際には必要ではありません
xargs
。上記のコマンドを次のように簡略化できます。$ mv -- $(ls -ltr | grep -v '^d' | awk 'NR==2 { print $NF; exit }') ../complete/
________
* Rahul の回答と同様に、ファイル名にスペースやタブが含まれている場合、これは失敗します。改行が含まれている場合はさらに悪い結果になります。
名前がピリオド(.
)、shopt -s dotglob
行う前に
$ mv -- * ../error/