Comment puis-je faire en sorte que ls trie les caractères de soulignement en premier?

20

J'aime pouvoir nommer des fichiers et des répertoires avec un préfixe de soulignement si c'est quelque chose que je veux garder séparé des autres fichiers et répertoires au même niveau. Sous Windows et Mac, par exemple, le préfixe d'un fichier avec un trait de soulignement le trie en haut, devant les fichiers commençant par un caractère alphanumérique.

Mon googling s'est avéré que cela a à voir avec le LC_COLLATE et mes paramètres régionaux actuels (en_US). C'est bien, même si je ne comprends vraiment pas pourquoi en_US ne trie pas comme prévu.

Sur la base du paramètre de site de démonstration ICU Collate, en_US_POSIX semble certainement avoir l'ordre de tri que je recherche (vous devez modifier les exemples de données et ajouter des traits de soulignement pour les tester). Mais je ne vois pas vraiment comment appliquer cela dans mon shell Linux.

Idéalement, j'aimerais pouvoir configurer quelque chose dans ma configuration bash afin que ls trie toujours les soulignés en premier. Comment pourrais-je procéder?

Tom Auger
la source
Je ne peux pas reproduire en utilisant ICU Collate avec les valeurs par défaut ou avec en_US_POSIX.txt via "Fetch rules for locale". Pouvez-vous expliquer les paramètres que vous avez utilisés?
Mikel
Question similaire askubuntu.com/questions/47702/…
Mikel
@Mikel en utilisant le lien que j'ai fourni ci-dessus, ajoutez quelques traits de soulignement aux données de test, puis soumettez-les pour voir les résultats du tri.
Tom Auger
C'est exactement ce que j'ai fait, et les chaînes commençant par des traits de soulignement sont triées au milieu plutôt qu'au début, comme si les traits de soulignement n'étaient pas là.
Mikel
1
Une question connexe, qui concerne la modification de la définition de l'ordre de classement, est unix.stackexchange.com/questions/421908 .
JdeBP

Réponses:

5

Si vous ne parvenez pas lsà trier comme vous le souhaitez, essayez l'expansion du shell.

Vous pouvez utiliser des modèles de nom de fichier pour exécuter lsavec une liste de fichiers que le shell a déjà triés, en contournant la méthode qui lsutilise.

ls -lf _* [!_]*

En supposant que vous ayez les fichiers

_a a _b b _c c

c'est comme courir

ls -lf _a _b _c a b c

Explication:

_* est un modèle de shell correspondant à n'importe quel nom de fichier commençant par un trait de soulignement, développé par ordre alphabétique.

[!_]*correspond à tout nom de fichier ne commençant pas par un trait de soulignement, développé par ordre alphabétique.

-findique lsde ne pas trier, car le shell l'a déjà fait.

Pour plus d'informations: expansion du nom de fichier bash

S'il y a des répertoires dans le répertoire courant, vous voudrez exécuter la commande comme ceci pour éviter que ls ne liste les fichiers dans les répertoires:

ls -lfd _* [!_]*
Mikel
la source
7
Soit dit en passant, DOS / Windows / OSX ne mettent pas vraiment les traits de soulignement avant toute autre chose: ils trient sans respect de la casse avec le trait de soulignement placé avant les lettres, mais certains autres caractères de ponctuation vont avant ou après le trait de soulignement. L'utilisation _pour faire apparaître les fichiers en premier est un hack spécifique au système d'exploitation; et la version unix de ce hack consiste à démarrer le nom de fichier avec une lettre majuscule: la convention unix par défaut est d'utiliser uniquement des lettres minuscules dans les noms de fichiers.
Gilles 'SO- arrête d'être méchant'
4
Ou des zéros; par exemple 00README.
mattdm
1
@Gilles +1 pour la meilleure pratique unix d'utilisation des majuscules sur les fichiers importants pour les rendre ls en premier. À la fin de la journée, si c'est la convention, il est probablement préférable que j'adopte simplement cela, plutôt que d'essayer de forcer Unix à se comporter comme les autres systèmes d'exploitation afin que je puisse utiliser des conventions développées pour Mac ou Windows. Merci pour le bon conseil.
Tom Auger
1
@TomAuger -fdit de lsne pas faire son propre tri, il affiche donc ses arguments dans l'ordre de leur passage. Le résultat de chaque l'expansion générique de la coquille _*et [!_]*est une liste triée lexicographiquement.
Gilles 'SO- arrête d'être méchant'
1
@TomAuger Les arguments de lssont triés (en deux groupes: les premiers _, puis les autres) lorsqu'ils sont générés par le shell. Courez echo ls -lf _* [!_]*pour voir ce qui se passe. Le -fdrapeau indique de lsne faire aucun tri.
Gilles 'SO- arrête d'être méchant'
16

Si vous ne souhaitez pas mélanger les minuscules et les majuscules, définissez vos paramètres régionaux sur C, qui prend les caractères dans leur ordre numérique. _se situe entre les majuscules et les minuscules.

$ LC_COLLATE=C ls    
BAR  FOO  _score  _under  hello  world
$ LC_COLLATE=en_US ls                    
BAR  FOO  hello  _score  _under  world

Les paramètres régionaux LC_MESSAGES(langue des messages d'erreur), LC_CTYPE(jeux de caractères) et LC_TIME(format de date et d'heure) sont très utiles. LC_COLLATEet LC_NUMERICsont généralement plus problématiques qu'ils n'en valent, je ne recommande pas de les régler. Un tri lexicographique approprié est plus compliqué que LC_COLLATEprévu, et il peut provoquer toutes sortes de comportements étranges lorsque vous utilisez des plages de caractères dans les expressions régulières. LC_NUMERICest surtout cosmétique, sauf lorsque quelque chose tourne mal car un programme a produit un nombre avec un séparateur décimal autre que ..

Gilles 'SO- arrête d'être méchant'
la source
+1 Très intéressant. Donc, en utilisant ce formulaire, vous définissez temporairement la variable d'environnement LC_COLLATE juste pour cette seule instance de ls? Est-ce correct?
Tom Auger
1
Est-il possible de faire apparaître les traits de soulignement AVANT les majuscules?
Tom Auger
1
@TomAuger Oui, VAR=value cmdensembles VARà valueseulement dans l'environnement cmdet ne touche pas la valeur (ou l' absence de valeur) dans la coquille où vous l' exécutez. Pour que le trait de soulignement apparaisse avant les majuscules, vous devez définir vos propres paramètres régionaux. C'est possible, mais difficile à utiliser, car au moins sous Linux, la bibliothèque standard ne recherche que les définitions de paramètres régionaux dans /usr/lib/locale- il n'y a pas de ~/.localevariable d'environnement où vous pouvez mettre votre en_tomparamètre.
Gilles 'SO- arrête d'être méchant'
@TomAuger S'il s'agit uniquement de la lscommande, suivez la suggestion de Mikel .
Gilles 'SO- arrête d'être méchant'
2

Malheureusement, Linux utilise glibc pour ses informations locales, pas ICU, il n'y a donc aucun moyen de l'appliquer directement à Linux sans dépenser beaucoup d'efforts soit en modernisant ICU dans glibc, soit en complétant les informations locales dans glibc.

Ignacio Vazquez-Abrams
la source
-4

L'ajout du -fcommutateur (pas de tri) l'a montré de cette façon pour moi.

man ls

[root@dusknoir ~/java/test]# ls -fl
total 0
-rw-r--r--  1 root  wheel  0 Jun  1 13:27 _1
-rw-r--r--  1 root  wheel  0 Jun  1 13:27 _2
-rw-r--r--  1 root  wheel  0 Jun  1 13:27 _3
-rw-r--r--  1 root  wheel  0 Jun  1 13:27 1
-rw-r--r--  1 root  wheel  0 Jun  1 13:27 2
-rw-r--r--  1 root  wheel  0 Jun  1 13:27 3
Tim
la source
6
Seulement parce que c'est ainsi qu'ils sont stockés dans le système de fichiers.
Ignacio Vazquez-Abrams
3
Désolé, mais cette réponse est tout à fait fausse. Test: touch 3 1 _1 _3 2 _2 && ls -flsorties2 . 1 3 _2 _3 .. _1
Marco