web-dev-qa-db-fra.com

Trier la sortie de find -exec ls

Est-il possible de la sortie de find … -exec ls -ls ; trié par ordre alphabétique, par nom de fichier?

Voici ma commande cron:

find /home/setefgge/public_html -type f -ctime -1 -exec ls -ls {} \;

Cette commande fonctionne bien, pour la plupart. Mais les résultats ne sont pas triés dans une séquence significative. Il serait très utile de les trier par le champ du nom de fichier.

14
MaJ

Je suppose que vos noms de fichiers ne contiennent pas de retours à la ligne.

find /home/setefgge/public_html -type f -ctime -1 -exec ls -nls {} + | sort -k 10

L'utilisation de + Au lieu de ; Pour terminer l'action -exec Accélère la procédure en regroupant les appels de ls. Vous pouvez trier en passant par la commande sort; dites-lui de commencer le tri au 10e champ (les 9 premiers sont les métadonnées: blocs, autorisations, nombre de liens, utilisateur, groupe, taille et 3 champs date/heure). L'option -n Indique à ls d'utiliser des valeurs numériques pour l'utilisateur et le groupe, ce qui évite le risque que les noms d'utilisateur ou de groupe contiennent des espaces.

Alternativement, avec zsh, vous pouvez vous en sortir sans aucune hypothèse sur n'importe quel nom en utilisant qualificatifs glob pour collecter et trier les fichiers et zargs pour exécuter ls plusieurs fois si la ligne de commande est trop longue. Vous avez besoin de GNU ls (en particulier son option -f) Pour éviter un nouveau tri par ls (une autre approche serait d'émuler ls avec zsh zstat ).

autoload -U zargs
zargs -- /home/setefgge/public_html/**/*(.c-2) -- ls -lnsf

POSIX a ceci à dire sur les dates dans un ls-long liste:

Le <date and time> Le champ doit contenir la date et l'horodatage appropriés de la dernière modification du fichier. Dans l'environnement local POSIX, le champ doit être l'équivalent de la sortie de la commande de date suivante:

date "+%b %e %H:%M"

... si le fichier a été modifié au cours des six derniers mois, ou:

date "+%b %e %Y"

En tenant compte de cela, et en vous assurant que s'il y a des sauts de ligne dans un nom de fichier, ils sont correctement globalisés avec le _ également spécifié par POSIX ls -q, il est relativement facile de préparer une expression régulière pour un résultat ls sans find du tout:

d=$(date "+%b %e") y=$(date --date=yesterday "+%b %e")
echo "$d" "$y"

###OUTPUT###
Jul  5 Jul  4

grep pour cela et vous ne retournerez que des lignes contenant les chaînes représentant les dates d'aujourd'hui ou d'hier. La commande suivante ajoute un peu à cela:

ls -alRcq | sed "1H;/^-/!{/./d;N;h};/$d\|$y/!d;x;/\n/p;g"

ls les options comprennent:

  1. -a renvoie tous les fichiers d'un répertoire - y compris ceux qui commencent par .dot
  2. -l longue liste
  3. -R liste récursivement tous les répertoires enfants
  4. -c afficher l'heure de modification plutôt que l'heure d'accès
  5. -q retourner le Shell glob ? plutôt que non imprimable ou \tab caractères dans un nom de fichier

Ces résultats sont transmis sur le |pipe fichier vers sed qui correspond uniquement:

  1. La ligne vide précédant un chemin et la ligne suivante
  2. Lignes commençant par - (en d'autres termes - pas d pour le répertoire) qui contient également votre date.
  3. Cependant, il n'imprime pas les lignes de chemin sauf si le répertoire qu'ils nomment contient réellement les fichiers pour lesquels vous avez filtré.

La sortie ressemble à ceci:

ls -alRcq --color=always | 
sed "1H;/^-/!{/./d;N;h};/$d\|$y/!d;x;/\n/p;g"

###OUTPUT###
.:
-rw------- 1 mikeserv mikeserv   2086 Jul  4 10:52 .bash_history
-rw------- 1 mikeserv mikeserv   2657 Jul  4 15:20 .lesshst
-rw-r--r-- 1 mikeserv mikeserv    681 Jul  5 05:18 .zdirs
-rw------- 1 mikeserv mikeserv 750583 Jul  5 08:28 .zsh_history
-rw-r--r-- 1 mikeserv mikeserv    166 Jul  4 23:02 Terminology.log
-rw-r--r-- 1 mikeserv mikeserv 433568 Jul  4 13:34 shot-2014-06-22_17-10-16.jpg
-rw-r--r-- 1 mikeserv mikeserv 445192 Jul  4 13:34 shot-2014-06-22_17-11-06.jpg

./.cache/efreet:
-rw------- 1 mikeserv mikeserv  37325 Jul  4 22:51 desktop_localhost_C.eet
-rw------- 1 mikeserv mikeserv  37325 Jul  4 23:30 desktop_localhost_en_US.eet
-rw------- 1 mikeserv mikeserv  24090 Jul  4 22:51 desktop_util_localhost_C.eet
-rw------- 1 mikeserv mikeserv  24090 Jul  4 23:30 desktop_util_localhost_en_US.eet
-rw------- 1 mikeserv mikeserv  16037 Jul  4 23:30 icon_themes_localhost.eet
-rw------- 1 mikeserv mikeserv   3117 Jul  4 23:30 icons___efreet_fallback_localhost.eet
-rw------- 1 mikeserv mikeserv 768039 Jul  4 23:30 icons_gnome_localhost.eet
-rw------- 1 mikeserv mikeserv  18589 Jul  4 23:30 icons_hicolor_localhost.eet

./.config:
-rw-r--r-- 1 mikeserv mikeserv   30 Jul  4 19:10 pavucontrol.ini

./.config/chrome:
-rw-r--r-- 1 mikeserv mikeserv 94332179 Jul  4 13:36 conf.tar.lz4.bak

Oui, cela fonctionne même avec LS_COLORS - ce qui est probablement une faible priorité pour votre cron bien sûr, mais bon, vos options sont ouvertes.

Dans tous les cas, cela offre des avantages importants par rapport à d'autres solutions possibles.

  1. En premier lieu find + ls implique plusieurs invocations - cela implique seulement un seul processus ls, et c'est pourquoi il est capable de tout trier de manière fiable - ce qu'il fait par par défaut - et donc sort est également rendu accessoire.

  2. Toute solution impliquant find et sort et ls fait à peu près tout deux fois le travail . ls et find résoudront tous les deux les chemins d'accès et stat tous les fichiers. ls et sort trieront tous les résultats. Il est probablement préférable d'utiliser à la place le seul ls.

  3. Bien sûr, il y a les parties date et sed de cette réponse. Ce qui est important à noter à ce sujet, c'est que vous faites la partie difficile et obtenez d'abord l'expression régulière - et une seule fois - et ensuite vous ne taillez qu'une seule liste de résultats plutôt que de dire, obtenir des résultats, obtenir des résultats, trier les résultats et trier les résultats.

  4. Cela ne se casse pas sur les noms de fichiers contenant des sauts de ligne, comme le feront probablement d'autres solutions. Cette solution a ses propres mises en garde - que j'explique ensuite - mais elles sont infimes et faciles à gérer. À mon avis, c'est la solution la plus robuste ici.

Il existe deux cas dans lesquels la commande ci-dessus peut vous poser des problèmes. Le premier implique le ? globs dans les noms de fichiers - alors que tel est déjà une solution plus robuste que toute autre proposée ici, et la probabilité que vous rencontriez un ? du tout est assez petit en soi, il est possible que la résolution de ces globes corresponde à plusieurs noms de fichiers. Veuillez consulter this pour plus d'informations à ce sujet.

L'autre possibilité implique un faux positif - par exemple si vous avez un nom de fichier correspondant réellement à la chaîne date que nous recherchons avec grep mais qui n'a pas été réellement modifié aucun de ces jours. Je ne compte pas sur le fait que ce soit un problème, mais, si c'est le cas, posez des questions à ce sujet et je peux probablement vous aider à rendre l'expression plus précise afin de gérer cela.

1
mikeserv

Pourquoi ne pas diriger le résultat de la recherche par tri, puis exécuter ls pour chacune des lignes?

find . -type f -ctime -1 | sort | while IFS= read -r filename; do ls -ls "$filename"; done
1
groxxda

Vous pouvez réellement utiliser une combinaison de find, xargs et ls.

Voici un exemple de commande: find . -type f -print0 | xargs -0 ls -lt

  • find recherchera récursivement tous les fichiers du répertoire courant.
  • xargs transmettra cette liste de fichiers à la commande ls en un seul appel (à condition que find renvoie moins de ARG_MAX des dossiers).
  • ls -lt triera ces fichiers par heure et formatera la sortie

Afin de récupérer votre système ARG_MAX vous pouvez taper:

$ getconf ARG_MAX
> 2621440
0
Max