Système d'exploitation: Linux
Type de système de fichiers: ext3
Solution préférée: bash (script/oneliner), Ruby, python
J'ai plusieurs répertoires avec plusieurs sous-répertoires et fichiers. Je dois faire une liste de tous ces répertoires construite de manière à ce que chaque répertoire de premier niveau soit répertorié à côté de la date et de l'heure du dernier fichier créé/modifié qu'il contient.
Pour clarifier, si je touche un fichier ou modifie son contenu quelques niveaux plus bas, l'horodatage doit être affiché à côté du nom du répertoire de premier niveau. Disons que j'ai un répertoire structuré comme ceci:
./alfa/beta/gamma/example.txt
et je modifie le contenu du fichier example.txt
, il me faut cette heure affichée à côté du répertoire de premier niveau alfa
sous une forme lisible par l'homme, et non pas Epoch. J'ai essayé certaines choses en utilisant find, xargs
, sort
et les goûts, mais je ne parviens pas à résoudre le problème selon lequel l'horodatage du système de fichiers de 'alfa' ne change pas lorsque je crée/modifie des fichiers quelques niveaux plus bas.
Essaye celui-là:
#!/bin/bash
find $1 -type f -exec stat --format '%Y :%y %n' "{}" \; | sort -nr | cut -d: -f2- | head
Exécutez-le avec le chemin du répertoire où il doit commencer à analyser de manière récursive (il prend en charge les noms de fichiers avec des espaces).
S'il y a beaucoup de fichiers, cela peut prendre un certain temps avant que rien ne soit renvoyé. Les performances peuvent être améliorées si nous utilisons plutôt xargs
:
#!/bin/bash
find $1 -type f -print0 | xargs -0 stat --format '%Y :%y %n' | sort -nr | cut -d: -f2- | head
ce qui est un peu plus rapide.
Pour trouver tous les fichiers dont le statut a été modifié pour la dernière fois N il y a quelques minutes:
find -cmin -N
par exemple:
find -cmin -5
La recherche GNU (voir man find
) a un paramètre -printf
permettant de déplacer les fichiers EPOC mtime et le nom de chemin relatif.
redhat> find . -type f -printf '%T@ %P\n' | sort -n | awk '{print $2}'
J'ai raccourci la réponse impressionnante de halo à ce one-liner
stat --printf="%y %n\n" $(ls -tr $(find * -type f))
Mise à jour: S'il y a des espaces dans les noms de fichiers, vous pouvez utiliser cette modification
OFS="$IFS";IFS=$'\n';stat --printf="%y %n\n" $(ls -tr $(find . -type f));IFS="$OFS";
Essaye ça
#!/bin/bash
stat --format %y $(ls -t $(find alfa/ -type f) | head -n 1)
Il utilise find
pour rassembler tous les fichiers du répertoire, ls
pour les répertorier par date de modification, head
pour sélectionner le 1er fichier et enfin stat
pour afficher l'heure. un beau format.
Pour le moment, les noms de fichiers comportant des espaces ou d'autres caractères spéciaux ne sont pas sûrs. Rédigez une recommandation si elle ne répond pas encore à vos besoins.
Cette commande fonctionne sur Mac OS X:
find "$1" -type f -print0 | xargs -0 stat --format '%Y :%y %n' | sort -nr | cut -d: -f2- | head
Sous Linux, comme l'a demandé l'affiche originale, utilisez stat
au lieu de gstat
.
Cette réponse est, bien sûr, la solution exceptionnelle de ser37078 , promue du commentaire à la réponse complète. J'ai mélangé à la perspicacité de CharlesB pour utiliser gstat
sur Mac OS X. J'ai obtenu de coreutils de - MacPorts plutôt que homebrew , au fait.
Et voici comment j'ai intégré cela dans une simple commande ~/bin/ls-recent.sh
pour le réutiliser:
#!/bin/bash
# ls-recent: list files in a dir tree, most recently modified first
#
# Usage: ls-recent path [-10 | more]
#
# Where "path" is a path to target directory, "-10" is any arg to pass
# to "head" to limit the number of entries, and "more" is a special arg
# in place of "-10" which calls the pager "more" instead of "head".
if [ "more" = "$2" ]; then
H=more; N=''
else
H=head; N=$2
fi
find "$1" -type f -print0 |xargs -0 gstat --format '%Y :%y %n' \
|sort -nr |cut -d: -f2- |$H $N
Les solutions Perl et Python de ce message m'ont aidé à résoudre ce problème sous Mac OS X: https://unix.stackexchange.com/questions/9247/how-to-list-files -sorted-by-modification-date-récursivement-no-stat-commande-avail .
Citation de l'article:
Perl:
find . -type f -print |
Perl -l -ne '
$_{$_} = -M; # store file age (mtime - now)
END {
$,="\n";
print sort {$_{$b} <=> $_{$a}} keys %_; # print by decreasing age
}'
Python:
find . -type f -print |
python -c 'import os, sys; times = {}
for f in sys.stdin.readlines(): f = f[0:-1]; times[f] = os.stat(f).st_mtime
for f in sorted(times.iterkeys(), key=lambda f:times[f]): print f'
Je montre ceci pour la dernière heure d'accès, vous pouvez facilement le modifier pour faire les dernières modifications.
Il y a deux façons de faire cela:
1) Si vous voulez éviter le tri global qui peut coûter cher si vous avez des dizaines de millions de fichiers, alors vous pouvez faire: (positionnez-vous à la racine du répertoire où vous voulez que votre recherche commence)
linux> touch -d @0 /tmp/a;
linux> find . -type f -exec tcsh -f -c test `stat --printf="%X" {}` -gt `stat --printf="%X" /tmp/a` ; -exec tcsh -f -c touch -a -r {} /tmp/a ; -print
La méthode ci-dessus imprime les noms de fichiers avec le temps d'accès le plus récent et le dernier fichier imprimé est le fichier avec le dernier temps d'accès. Vous pouvez évidemment obtenir la dernière heure d'accès en utilisant un "tail -1".
2) Vous pouvez faire en sorte d’imprimer récursivement le nom, l’heure d’accès de tous les fichiers de votre sous-répertoire, puis trier en fonction de l’heure d’accès et de la fin de la plus grande entrée:
linux> \find . -type f -exec stat --printf="%X %n\n" {} \; | \sort -n | tail -1
Et voila...
Gère bien les espaces dans les noms de fichiers - vous ne devez pas les utiliser!
$ find . -type f -not -path '*/\.*' -printf '%TY.%Tm.%Td %THh%TM %Ta %p\n' |sort -nr |head -n 10
2017.01.28 07h00 Sat ./recent
2017.01.21 10h49 Sat ./hgb
2017.01.16 07h44 Mon ./swx
2017.01.10 18h24 Tue ./update-stations
2017.01.09 10h38 Mon ./stations.json
Plus find
Galore peut être trouvé en suivant le lien.
J'ai cet alias dans mon .profile que j'utilise assez souvent
$ alias | grep xlogs
xlogs='Sudo find . \( -name "*.log" -o -name "*.trc" \) -mtime -1 | Sudo xargs ls -ltr --color | less -R'
Donc, il fait ce que vous recherchez (sauf qu'il ne traverse pas plusieurs niveaux de date/heure de modification) - recherche les fichiers les plus récents (fichiers * .log et * .trc dans ce cas); de plus, il ne trouve que les fichiers modifiés le dernier jour, puis trie par heure et passe en sortie avec moins:
Sudo find . \( -name "*.log" -o -name "*.trc" \) -mtime -1 | Sudo xargs ls -ltr --color | less -R
ps. Remarquez que je n'ai pas de racine sur certains serveurs, mais que j'ai toujours Sudo, vous n'aurez peut-être pas besoin de cette partie.
Voici une version qui fonctionne avec les noms de fichiers pouvant contenir des espaces, des nouvelles lignes et des caractères globaux:
find . -type f -printf "%T@ %p\0" | sort -zk1nr
find ... -printf
affiche la modification du fichier (valeur d'époque) suivie d'un espace et de _ noms de fichiers terminés \0
.sort -zk1nr
lit les données terminées par NUL et les trie en sens inverseComme la question est étiquetée avec Linux, je suppose donc que gnu
utils sont disponibles.
Vous pouvez diriger dessus avec:
xargs -0 printf "%s\n"
pour imprimer l’heure de modification et les noms de fichiers triés par heure de modification (le plus récent en premier) et terminés par une nouvelle ligne.
Fonction de bash rapide:
# findLatestModifiedFiles(directory, [max=10, [format="%Td %Tb %TY, %TT"]])
function findLatestModifiedFiles() {
local d="${1:-.}"
local m="${2:-10}"
local f="${3:-%Td %Tb %TY, %TT}"
find "$d" -type f -printf "%T@ :$f %p\n" | sort -nr | cut -d: -f2- | head -n"$m"
}
Recherchez le dernier fichier modifié dans un répertoire:
findLatestModifiedFiles "/home/jason/" 1
Vous pouvez également spécifier votre propre format de date/heure comme troisième argument.
Ce qui suit vous renvoie une chaîne d'horodatage et le nom du fichier avec l'horodatage le plus récent:
find $Directory -type f -printf "%TY-%Tm-%Td-%TH-%TM-%TS %p\n" | sed -r 's/([[:digit:]]{2})\.([[:digit:]]{2,})/\1-\2/' | sort --field-separator='-' -nrk1 -nrk2 -nrk3 -nrk4 -nrk5 -nrk6 -nrk7 | head -n 1
Résultat en une sortie de la forme: <yy-mm-dd-hh-mm-ss.nanosec> <filename>
Vous pouvez donner à la commande printf de trouver un essai
% Dernier accès du fichier Ak au format spécifié par k, qui est soit la fonction
@' or a directive for the C
strftime '. Les valeurs possibles pour k sont énumérées ci-dessous; certains d'entre eux peuvent ne pas être disponibles sur tous les systèmes, en raison des différences de "strftime" entre les systèmes.
C'est ce que j'utilise (très efficace):
function find_last () { find "${1:-.}" -type f -printf '%TY-%Tm-%Td %TH:%TM %P\n' 2>/dev/null | sort | tail -n "${2:-10}" }
AVANTAGES:
USAGE:
find_last [dir [number]]
où:
dir
- un répertoire à rechercher [répertoire actuel]number
- nombre de fichiers les plus récents à afficher [10]La sortie pour find_last /etc 4
ressemble à ceci:
2019-07-09 12:12 cups/printers.conf
2019-07-09 14:20 salt/minion.d/_schedule.conf
2019-07-09 14:31 network/interfaces
2019-07-09 14:41 environment
Cela pourrait être fait avec une fonction reccursive dans bash aussi
Soit F une fonction qui affiche l’heure du fichier qui doit pouvoir être triée lexicographiquement aaaa-mm-jj etc., (dépendante de l’os?)
F(){ stat --format %y "$1";} # Linux
F(){ ls -E "$1"|awk '{print$6" "$7}';} # SunOS: maybe this could be done easier
R la fonction récursive qui traverse les répertoires
R(){ local f;for f in "$1"/*;do [ -d "$f" ]&&R $f||F "$f";done;}
Et enfin
for f in *;do [ -d "$f" ]&&echo `R "$f"|sort|tail -1`" $f";done
Utilisez ceci pour la sortie simple ls
. Il n'y a pas de liste d'arguments, donc ça ne peut pas être trop long:
find . | while read FILE;do ls -d -l "$FILE";done
Et sympa avec cut
pour seulement les dates, les heures et le nom:
find . | while read FILE;do ls -d -l "$FILE";done | cut --complement -d ' ' -f 1-5
EDIT: Je viens de remarquer que la réponse la plus récente est classée par date de modification. C'est tout aussi facile avec le deuxième exemple ici, puisque la date de modification est la première sur chaque ligne - claquez un tri sur la fin:
find . | while read FILE;do ls -d -l "$FILE";done | cut --complement -d ' ' -f 1-5 | sort