In meinem Verzeichnis befinden n
sich mehrere Dateien ../in/
. Von diesen Dateien möchte ich die älteste Datei verarbeiten und an das ../complete/
Verzeichnis senden. Die übrigen Dateien werden an das ../error/
Verzeichnis gesendet. Kann jemand helfen?
Antwort1
So kopieren Sie die älteste Datei nach ../complete
:
cp -v "$(find ../in -maxdepth 1 -type f -printf '%T@ %p\0' | sort -zn | \
sed -zn '1s/[0-9,\.]\+ //p')" ../complete
So kopieren Sie alles außer dem ältesten nach ../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
Erläuterung:
find
-maxdepth 1
geht nur eine Ebene nach unten; daher wird das Verzeichnis nicht rekursiv durchsucht.-type f
nur Dateien abgleichen.-printf '...'
ein benutzerdefiniertes Ausgabeformat.%T@
gibt den letzten Änderungszeitpunkt der Datei in einem Zeitstempel an,%p
ist der Name der Datei. Beachten Sie das\0
am Ende. Die Dateien werden durch Nullbytes getrennt gedruckt, nicht durch Zeilenumbrüche, da der Zeilenumbruch wahrscheinlich ein Zeichen im Dateinamen sein könnte, was dann den Befehl unterbrechen würde.
sort -zn
Dadurch wird die Ausgabe durch Null-Bytes getrennt () gelesen-z
und numerisch sortiert (-n
).sed -zn
liest die Ausgabe durch Null-Bytes getrennt.1
stimmt nur mit der ersten Zeile überein (erster Befehl) und2,$
mit allen anderen (zweiter Befehl)s/[0-9,\.]\+ //p
entfernt den führenden Zeitstempel aus der Ausgabe.
- Nur ab dem zweiten Befehl:
xargs -0 cp -vt ../error
Verarbeitet die Ausgabe durch Null-Bytes getrennt (-0
) und ruftcp -vt ../error
bei allen Eingaben auf, welche die Dateien kopieren.
Beispielausgabe:
$ 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'
Antwort2
Um die älteste Datei zu finden und sie in das gewünschte Verzeichnis zu verschieben, verwenden Sie:
# cd to ../in/
$ ls -lt | grep -v '^d' | tail -1 | awk '{print $NF}' | xargs -I '{}' mv '{}' ../complete/
Nachdem Ihre älteste Datei nun ausgelagert wurde, können Sie alle Dateien nach../error/
$ mv -- * ../error/
Das --
Folgende mv
ist erforderlich, wenn Ihre Datei-/Verzeichnisnamen mit einem beginnen -
.
Antwort3
Aufbauend aufRahuls Antwort:
$ ls -ltr | grep -v '^d' | awk 'NR==2 {print $NF; exit}' | xargs -I '{}' mv -- '{}' ../complete/
Anmerkungen:
- Sie sagen, Sie möchten etwas mit „der ältesten Datei“ machen. Alle Antworten gehen davon aus, dass Sie „am wenigsten kürzlich geändert“ meinen. Wenn Sie „am wenigsten kürzlich geändert“ meinengeändert, sagen Sie es; die Antworten werden etwas anders sein. Wenn Sie zuletzt meinenerstellt, was Sie wollen, ist unter Unix fast unmöglich.
ls -lt
(was Rahul verwendet hat) listet das aktuelle Verzeichnis im Langformat in der Reihenfolge nach Änderungsdatum/-zeit auf, wobei das Neueste zuerst und das Älteste zuletzt ist.ls -ltr
ist dasRalles davon; die ältesten zuerst und die neuesten zuletzt.- Wenn Sie möglicherweise Dateien haben, deren Namen mit einem Punkt beginnen (
.
), fügen Sie dieA
Option zu hinzuls
; z. B.ls -ltrA
. (Die Reihenfolge der Optionen ist egal; Sie könnenls -ltAr
,ls -lAtr
, oder sogar verwendenls -ltr -A
, wenn Sie möchten.) - Ich habe gelogen. Eine lange
ls
Auflistung eines Verzeichnisses hat immer einetotal
Zeile am Anfang. Inls -ltr
steht der älteste Eintrag auf derzweiteLinie. grep -v '^d'
filtert die Verzeichnisse heraus (sofern vorhanden).awk 'NR==2 { print $NF; exit }'
druckt das letzte Feld (den Dateinamen*) aus der zweiten Zeile (der ältesten Datei) und beendet dann das Programm.- Dies ist ein Prozess weniger als
tail -1 | awk '{print $NF}'
. - Dies könnte schneller funktionieren, da beim
awk
Beendenls
möglicherweise auch beendet wird und Sie so die Generierung der Liste für das gesamte Verzeichnis vermeiden würden. Sie können das Problem beseitigen,
grep
indem Sie Folgendes tun:ls -ltr | awk '! /^d/ { count++ } count==2 { print $NF; exit }'
aber ich würde davon abraten. Zu komplexe Skripte sind schwer zu warten.
- Dies ist ein Prozess weniger als
- Das
--
Danachmv
imxargs
Befehlist notwendig, wenn Sie Dateinamen haben, die mit einem beginnen-
. Sie brauchen das nicht wirklich
xargs
. Sie können den obigen Befehl vereinfachen zu$ mv -- $(ls -ltr | grep -v '^d' | awk 'NR==2 { print $NF; exit }') ../complete/
________
* Wie in Rahuls Antwort schlägt dies fehl, wenn der Dateiname Leerzeichen oder Tabulatoren enthält – und noch schlimmer, wenn er Zeilenumbrüche enthält.
Wenn Sie möglicherweise Dateien haben, deren Namen mit einem Punkt beginnen (.
), shopt -s dotglob
bevor Sie die
$ mv -- * ../error/