Trier la sortie de find -exec ls


14

Est-il possible de sortir des find … -exec ls -ls ;triés 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.


1
Vous utilisez zsh? ls -ls **/*(.)
Kevin

@Kevin Pas tout à fait - trierait ls.
Gilles 'SO- arrête d'être méchant'

Réponses:


14

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

Utiliser +au lieu de ;pour terminer l' -execaction accélère en regroupant les appels de ls. Vous pouvez trier en passant par la sortcommande; dites-lui de commencer à trier 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 -nindique lsd'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 des qualificatifs glob pour collecter et trier les fichiers et zargspour exécuter lsplusieurs fois si la ligne de commande est trop longue. Vous avez besoin de GNU ls(en particulier son -foption) pour éviter un nouveau tri par ls(une autre approche serait d'émuler lsavec des zsh zstat).

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

Merci beaucoup! La première commande que vous avez envoyée fait le tri. Le nombre serait-il toujours 10 si j'utilise un chemin plus court? Par exemple, si j'exécute la même commande depuis / home / setefgge au lieu de public_html?
MaJ

@MaJ 10 est le nombre de champs ignorés, cela n'a rien à voir avec la taille du nom de fichier.
Gilles 'SO- arrête d'être méchant'

Je vous remercie. J'apprécie votre aide, ainsi que l'aide fournie par tout le monde. Je considère que ce problème est résolu. Ma commande cron trie maintenant les fichiers. C'est la première fois que je soumets une question à Stackexchange. Je ne vois pas d'option "Résolu". Si certains d'entre vous savent comment publier ceci comme résolu, veuillez continuer et faites-le. Merci!
MaJ

@MaJ La chose la plus proche que nous avons pour marquer une question comme résolue est de marquer une des réponses comme acceptée. Seul vous, le demandeur, pouvez le faire. Pour ce faire, cliquez sur la coche à côté de la réponse qui vous a le plus aidé. Si vous acceptez une réponse, vous obtiendrez 2 points de réputation en plus, et après cela, vous pourrez voter en amont; vous pouvez voter pour tous les messages que vous avez trouvés utiles. Pour plus d'informations, consultez la page de visite et la page d'aide sur ce qu'il faut faire lorsque quelqu'un répond à votre question .
Gilles 'SO- arrête d'être méchant'

1

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

POSIX a ceci à dire sur les dates dans une ls -lliste ong:

Le <date and time>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 veillant à ce qu'il y ait des sauts de ligne dans un nom de fichier, ils sont correctement globalisés avec l' ls -qoption spécifiée POSIX également , il est relativement facile de préparer une expression régulière pour un lsrésultat sans find:

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

###OUTPUT###
Jul  5 Jul  4

greppour cela et vous ne renverrez 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 consistent en:

  1. -a retourner tous les fichiers dans un répertoire - y compris ceux qui commencent par un .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. -qretourner le shell glob ?plutôt que des caractères non imprimables ou \tab dans un nom de fichier

Ces résultats sont transmis au |pipefichier sedauquel correspond uniquement:

  1. La ligne vide précédant un chemin et la ligne suivante
  2. Les lignes commençant par - (en d'autres termes - pas dpour le répertoire) qui contiennent é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 vous cronbien sûr, mais, hé, vos options sont ouvertes.

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

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

  2. Toute solution impliquant findet sortet lsfait à peu près tout le travail deux fois. lset findrésoudra à la fois chaque chemin d'accès et statchaque fichier. lset sorttriera tous les résultats. Il est probablement préférable d'utiliser simplement le single ls.

  3. Ensuite, bien sûr, il y a les parties dateet sedde 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 les ?globes dans les noms de fichiers - alors que c'est déjà une solution plus robuste que toute autre proposée ici, et la probabilité que vous rencontriez un ?du tout est assez petite en soi, il est possible que la résolution de ces globs pourrait correspondre à plus d'un nom de fichier. S'il vous plaît voir ce 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 datechaîne pour laquelle nous recherchons, grepmais 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 régulière plus spécifique afin de gérer cela.


0

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 lscommande en un seul appel (à condition de findrenvoyer moins de ARG_MAXfichiers).
  • ls -lt triera ces fichiers par heure et formatera la sortie

Afin de récupérer votre système, ARG_MAXvous pouvez taper:

$ getconf ARG_MAX
> 2621440

-1
ls -l $(find /home/setefgge/public_html -type f -ctime -1 | sort)

1
lsfait son propre tri, donc canaliser la sortie de findthrough sortest inutile. De plus, votre commande modifie les noms de fichiers contenant des espaces (entre autres) et échouera s'il y a trop de noms de fichiers.
Gilles 'SO- arrête d'être méchant'
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.