cClaude.rocks ☕ Le blog

[Nouvelles technologies, sciences et coups de gueule…]

Menu

La commande df fournit la quantitĂ© d’espace occupĂ© des systĂšmes de fichiers, mais l’affichage n’est pas trĂšs pratique pour les scripts.

Présentation de la commande df

L’usage typique Ă©tant :

df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/root        29G  8.0G   20G  30% /
devtmpfs        454M     0  454M   0% /dev
tmpfs           487M     0  487M   0% /dev/shm
tmpfs           487M   50M  438M  11% /run
tmpfs           5.0M  4.0K  5.0M   1% /run/lock
tmpfs           487M     0  487M   0% /sys/fs/cgroup
/dev/mmcblk0p1  253M   49M  204M  20% /boot
tmpfs            98M     0   98M   0% /run/user/1000

L’option -p permet d’avoir un affichage plus prĂ©dictible sur six colonnes, mais avec une prĂ©sentation moins sympa.

df -Ph

ඏ

df au format JSON

À partir de cette Ă©criture, il est possible d’opĂ©rer avec jq une analyse du rĂ©sultat et reformater cela format JSON.

df -Ph | jq --raw-input --slurp '[ split("\n") | .[] | if test("^/") then gsub(" +"; " ") | split(" ") | {filesystem: .[0], total: .[1], used: .[2], avail: .[3], percent: .[4], mount: .[5]} else empty end ]'
  • Explications

    Voici le code sur plusieurs lignes, c’est clair, non ?

    df -Ph |
      jq --raw-input --slurp '[
      split("\n") |
      .[] |
      if test("^/") then
        gsub(" +"; " ") |
        split(" ") |
        {filesystem: .[0], total: .[1], used: .[2], avail: .[3], percent: .[4], mount: .[5]}
      else
        empty
      end
    ]'
    

    Détaillons encore :

    • df -Ph : C’est la commande initiale que l’on va analyser, notez que vous devez garde l’option -P, mais vous pouvez par exemple utiliser les unitĂ©s du systĂšme international --si en remplaçant par df -P --si.
    • | : indique que le rĂ©sultat sera utilisĂ© comme valeur d’entrĂ©e pour la commande suivante.
    • jq --raw-input --slurp 
 : la commande jq et ces paramĂštres

    Détail des paramÚtres de la commande jq :

    • --raw-input ou -R : Indique que ce qui est pris en entrĂ©e n’est pas du JSON mais du texte brut,
    • --slurp ou-s : Indique qu’il faut faire un tableau avec ce qu’on prend en entrĂ©e.
    • Ce qui se trouve entre ' 
 ' est le code jq qui sera exĂ©cutĂ©.

    Détail du code jq :

    [
      split("\n") |
      .[] |
      if test("^/") then
        gsub(" +"; " ") |
        split(" ") |
        {filesystem: .[0], total: .[1], used: .[2], avail: .[3], percent: .[4], mount: .[5]}
      else
        empty
      end
    ]
    
    • [ : Commence le tableau des rĂ©sultats.
    • split("\n") : met chaque ligne dans une chaĂźne de caractĂšre, cela construit au passage un nouveau tableau .
    • | : passe le rĂ©sultat Ă  la commande suivante.
    • .[] : traite Ă©lĂ©ment par Ă©lĂ©ment (donc ligne par ligne).
    • | : passe le rĂ©sultat Ă  la commande suivante.
    • if CONDITION then RESULTAT_VRAI else RESULTAT_FAUX end : en fonction d’une CONDITION on continue le traitement soit en gĂ©nĂ©rant RESULTAT_VRAI, soit en gĂ©nĂ©rant RESULTAT_FAUX.
      • CONDITION test("^/") : si la chaĂźne (donc la ligne) commence par ^ le caractĂšre / c’est vrai, sinon c’est faux.
      • RESULTAT_VRAI gsub(" +"; " ") | split(" ") | {filesystem: .[0], total: .[1], used: .[2], avail: .[3], percent: .[4], mount: .[5]} : dĂ©tail plus bas.
      • RESULTAT_FAUX empty : on ajoute rien
    • ] : Termine le tableau des rĂ©sultats.

    Détail du cas RESULTAT_VRAI qui est effectué sur chaque ligne :

    gsub(" +"; " ") |
    split(" ") |
    {filesystem: .[0], total: .[1], used: .[2], avail: .[3], percent: .[4], mount: .[5]}
    
    • gsub(" +"; " ") : Supprime tous les espaces en double, il ne restera plus qu’un seul espace entre les zones de texte.
    • | : passe le rĂ©sultat Ă  la commande suivante.
    • split(" ") : Construit un tableau contenant chaque zone de texte (donc on attend un tableau avec 6 Ă©lĂ©ments (indices de 0 Ă  5).
    • | : passe le rĂ©sultat Ă  la commande suivante.
    • {filesystem: .[0], total: .[1], used: .[2], avail: .[3], percent: .[4], mount: .[5]} : Construit l’élĂ©ment JSON attendu.

ඏ

Nettoyons les résultats qui ne sont pas nécessaires

On a déjà « nettoyé » quelques valeurs puisque les lignes ne commençant par / ont été ignorées, correspondant à des périphériques virtuels dont la taille, nous importe peu ainsi que la premiÚre ligne. Il reste encore de périphériques de type /dev/loop qui sont des artefacts permettant de rendre des fichiers ordinaires visibles en tant que périphériques de bloc (des disques). Ils sont généralement utilisés pour monter des images de disque (pour plus de détail : Loop device sur Wikipédia).

df -Ph | jq -R -s '[ split("\n") | .[] | if (test("^/") and (test("^/dev/loop") | not)) then gsub(" +"; " ") | split(" ") | {filesystem: .[0], total: .[1], used: .[2], avail: .[3], percent: .[4], mount: .[5]} else empty end ]'

Il reste encore le cas du caractùre % qui n’est pas un nombre facile à traiter, on va donc supprimer le caractùre et remplacer la chaüne par un nombre, comme suit :

df -Ph | jq -R -s '[ split("\n") | .[] | if (test("^/") and (test("^/dev/loop") | not)) then gsub(" +"; " ") | split(" ") | {filesystem: .[0], total: .[1], used: .[2], avail: .[3], percent: (.[4] | sub("%"; "") | tonumber), mount: .[5]} else empty end ]'
  • Vue dĂ©taillĂ©e
    df -Ph |
      jq -R -s '[
      split("\n") |
      .[] |
      if (test("^/") and (test("^/dev/loop") | not)) then
        gsub(" +"; " ") |
        split(" ") |
        {filesystem: .[0], total: .[1], used: .[2], avail: .[3], percent: (.[4] | sub("%"; "") | tonumber), mount: .[5]}
      else
        empty
      end
    ]'
    
  • RĂ©sultat
    [
      {
        "filesystem": "/dev/root",
        "total": "29G",
        "used": "8.0G",
        "avail": "20G",
        "percent": 30,
        "mount": "/"
      },
      {
        "filesystem": "/dev/mmcblk0p1",
        "total": "253M",
        "used": "49M",
        "avail": "204M",
        "percent": 20,
        "mount": "/boot"
      }
    ]
    

Si vous préférez avoir un résultat utilisant le systÚme métrique international, le changement est mineur :

df -P --si | jq -R -s '[ split("\n") | .[] | if (test("^/") and (test("^/dev/loop") | not)) then gsub(" +"; " ") | split(" ") | {filesystem: .[0], total: .[1], used: .[2], avail: .[3], percent: (.[4] | sub("%"; "") | tonumber), mount: .[5]} else empty end ]'

L’utilisation du systĂšme mĂ©trique international aura l’avantage de simplifier vos calculs, puisqu’on est sur une base 1000 et non plus 1024.


ඏ

Adaptation avec le type de systÚme de fichier :

Petit souci cette fois, car il va falloir tenir compte d’une colonne supplĂ©mentaire :

df -P --si -T | jq -R -s '[ split("\n") | .[] | if (test("^/") and (test("^/dev/loop") | not)) then gsub(" +"; " ") | split(" ") | {filesystem: .[0], type: .[1], total: .[2], used: .[3], avail: .[4], percent: (.[5] | sub("%"; "") | tonumber), mount: .[6]} else empty end ]'

Ce format reste Ă  mon sens insatisfaisant, car on se retrouve avec des chaĂźnes du type "31G", "8.6G", "265M", "51M" qui ne sont pas simples Ă  comparer.

Une solution consiste Ă  utiliser l’option -k pour tout passer en « kilo-bytes » et comme nous avons maintenant des valeurs numĂ©rique, il est conseille de changer de type.

df -P --si -T -k | jq -R -s '[ split("\n") | .[] | if (test("^/") and (test("^/dev/loop") | not)) then gsub(" +"; " ") | split(" ") | {filesystem: .[0], type: .[1], total: (.[2] | tonumber), used: (.[3] | tonumber) , avail: (.[4] | tonumber), percent: (.[5] | sub("%"; "") | tonumber), mount: .[6]} else empty end ]'

Ce qui donne :

[
  {
    "filesystem": "/dev/root",
    "type": "ext4",
    "total": 29609436,
    "used": 8315500,
    "avail": 20058496,
    "percent": 30,
    "mount": "/"
  },
  {
    "filesystem": "/dev/mmcblk0p1",
    "type": "vfat",
    "total": 258095,
    "used": 49243,
    "avail": 208853,
    "percent": 20,
    "mount": "/boot"
  }
]

Cependant, c’est clairement moins lisible par un ĂȘtre humain.

Considérations pour l'automatisation

Lors des tests, j’ai constatĂ© que la commande df pouvait ĂȘtre assez lente lorsque des disques rĂ©seaux sont montĂ©s.

L’usage de --exclude-type=cifs ou -x cifs est donc à envisager, en fonction de vos besoins.

df -P --si -T -k -x cifs -x tmpfs -x squashfs | jq -R -s '[ split("\n") | .[] | if (test("^/") and (test("^/dev/loop") | not)) then gsub(" +"; " ") | split(" ") | {filesystem: .[0], type: .[1], total: (.[2] | tonumber), used: (.[3] | tonumber) , avail: (.[4] | tonumber), percent: (.[5] | sub("%"; "") | tonumber), mount: .[6]} else empty end ]'
  • Vue dĂ©taillĂ©e
    df -P --si -T -k -x cifs -x tmpfs -x squashfs |
      jq -R -s '[
      split("\n") |
      .[] |
      if (test("^/") and (test("^/dev/loop") | not)) then
        gsub(" +"; " ") |
        split(" ") |
        {filesystem: .[0], type: .[1], total: (.[2] | tonumber), used: (.[3] | tonumber) , avail: (.[4] | tonumber), percent: (.[5] | sub("%"; "") | tonumber), mount: .[6]}
      else
        empty
      end
    ]'
    

ඏ

Avoir la version utilisable pour les calculs et lisible rapidement par un humain

C’est possible, mais c’est un peu lourd Ă  Ă©crire en gardant la solution en ligne de commande.

  • L’idĂ©e gĂ©nĂ©rale est la suivante
    df -P --si -T -k -x cifs -x tmpfs -x squashfs | jq -R -s -S '[
      split("\n") |
      .[] |
      if (test("^/") and (test("^/dev/loop") | not)) then
        gsub(" +"; " ") |
        split(" ") |
        {filesystem: .[0], type: .[1], total: (.[2] | tonumber), used: (.[3] | tonumber) , avail: (.[4] | tonumber), percent: (.[5] | sub("%"; "") | tonumber), mount: .[6]}
        | . + {
          "total-human": (
            if .total < 1000 then
              .total | tostring
            elif .total < 1000000 then
              (.total / 1000) | floor | tostring + "MB"
            else
              (.total / 1000000) | floor | tostring + "GB"
            end
          ),
          "used-human": (
            if .used < 1000 then
              .used | tostring
            elif .used < 1000000 then
              (.used / 1000) | floor | tostring + "MB"
            else
              (.used / 1000000) | floor | tostring + "GB"
            end
          ),
          "avail-human": (
            if .avail < 1000 then
              .avail | tostring
            elif .avail < 1000000 then
              (.avail / 1000) | floor | tostring + "MB"
            else
              (.avail / 1000000) | floor | tostring + "GB"
            end
          )
        }
      else
        empty
      end
    ]'
    

L’astuce consiste Ă  reprendre la ligne et Ă  ajouter des champs en utilisant les valeurs prĂ©alablement obtenues cela se fait grĂące Ă  la sĂ©quence | . +.

La version ultime

Vous allez devoir créer un fichier df-to-json.jq avec le contenu suivant :

  • df-to-json.jq
    def convert_number_to_human(n):
      n | if . < 1000 then
            . | tostring
          elif . < 1000000 then
            (./ 1000) | floor | tostring + "MB"
          elif . < 1000000000 then
            (./ 1000000) | floor | tostring + "GB"
          else
            (. / 1000000000) | floor | tostring + "TB"
          end
    ;
    
    def convert_df_to_json:
    [
      split("\n") |
      .[] |
      if (test("^/") and (test("^/dev/loop") | not)) then
        gsub(" +"; " ") |
        split(" ") |
        {filesystem: .[0], type: .[1], total: (.[2] | tonumber), used: (.[3] | tonumber) , avail: (.[4] | tonumber), percent: (.[5] | sub("%"; "") | tonumber), mount: .[6]}
        | . + {
          human: {
            total: convert_number_to_human( .total ),
            used: convert_number_to_human( .used ),
            avail: convert_number_to_human( .avail )
          }
        }
      else
        empty
      end
    ];
    
    convert_df_to_json
    

et vous l’utiliserez comme suit :

df -P --si -T -k -x tmpfs -x squashfs | jq -f 'df-to-json.jq'  -R -s -S

Bien évidement, vous devrez adapter pour tenir compte du chemin réel vers le fichier df-to-json.jq.

Et cela vous donnera quelque chose comme :

  • RĂ©sultat type
    [
      {
        "avail": 160723272,
        "filesystem": "/dev/nvn1p2",
        "human": {
          "avail": "160GB",
          "total": "244GB",
          "used": "71GB"
        },
        "mount": "/",
        "percent": 31,
        "total": 244568380,
        "type": "ext4",
        "used": 71352052
      },
      {
        "avail": 517892,
        "filesystem": "/dev/nvn1p1",
        "human": {
          "avail": "517MB",
          "total": "523MB",
          "used": "5MB"
        },
        "mount": "/boot/efi",
        "percent": 2,
        "total": 523248,
        "type": "vfat",
        "used": 5356
      },
      {
        "avail": 73966904,
        "filesystem": "/dev/sda1",
        "human": {
          "avail": "73GB",
          "total": "960GB",
          "used": "837GB"
        },
        "mount": "/mnt/data",
        "percent": 92,
        "total": 960379920,
        "type": "ext4",
        "used": 837558592
      },
      {
        "avail": 4763213456,
        "filesystem": "//192.168.126.12/Share",
        "human": {
          "avail": "4TB",
          "total": "22TB",
          "used": "18TB"
        },
        "mount": "/media/Share",
        "percent": 80,
        "total": 22886119912,
        "type": "cifs",
        "used": 18122906456
      }
    ]
    

ඏ

Références

኿


Contexte

La recherche de doublons est un besoin assez frĂ©quent, l’implĂ©mentation en bash n’est pas nĂ©cessairement simple.

Je vous propose une solution trùs simple à mettre en Ɠuvre utilisant jq.


ඏ

Exemples

Pour rechercher une valeur en double, il faut mĂ©moriser cette valeur qu’on appellera la clĂ© et garder il faut Ă©galement mĂ©moriser un identificateur correspondant Ă  cette valeur.

De maniĂšre gĂ©nĂ©rale, vous devrez donc prĂ©voir du code pour construire la valeur de la clĂ© et un mĂ©canisme pour construire l’identificateur.

Cas d’un fichier texte

Supposons un fichier texte dans lequel on souhaite retrouver les lignes en doubles, sans changer l’ordre du fichier.

Dans ce cas la valeur Ă  mĂ©moriser est le contenu de la ligne (ce sera notre clĂ©) et l’identificateur sera, par exemple, le numĂ©ro de la ligne.

Il sera possible, par exemple, de supprimer les derniùres lignes en double, sans pour autant changer l’ordre du fichier.

Cas de fichiers sur le disque

Si on souhaite rechercher des fichiers ayant le mĂȘme contenu dans une arborescence donnĂ©e, la clĂ© devient le contenu du fichier, comme cela n’est pas acceptable (trop de mĂ©moire et trop lent), on passe par un calcul de hachage, par exemple Ă  l’aide de sha512sum et, dans ce cas, l’identificateur sera le nom du fichier.


ඏ

L’algorithme

Initialisation

L’initialisation est Ă  faire une seule fois au dĂ©but du traitement. On va utiliser une variable globale pour rĂ©pondre au cas gĂ©nĂ©ral.

declare -g _entries_json_='{}'

Il s’agit ici de construire un objet JSON vide.

Itération

_key_=
Le truc potentiellement en double

_id_=
Un truc permettant d’identifier les doubles

_entries_json_="$(
  jq -c --arg key "${_key_}" --arg id "${_id_}" '.[$key] |= .+ [ $id ]' <<<"${_entries_json_}"
  )"

Attention, la clĂ© doit est une chaĂźne de caractĂšre raisonnable : en particulier, elle ne doit pas ĂȘtre trop longue.

RĂ©sultat

Une fois toutes les valeurs stockĂ©es dans la structure JSON, on supprime toutes les entrĂ©es qui n’ont pas de double :

_resultat_="$(
  jq '[ to_entries[] | select( .value | length >1 ) ] | from_entries' <<<"${_entries_json_}"
  )"

Et pour dĂ©tecter s’il y a des doubles, il suffit regarder le nombre d’entrĂ©es, par exemple :

if [ -n "$( jq -r 'to_entries[] | length' <<<"${_resultat_}" )" ] ; then
  echo 'Les doubles:'
  jq '.' <<<"${_resultat_}"
else
  echo 'Pas de double'
fi

Exemple de code concret

La bibliothĂšque:

function init_duplicate {
  declare -g _entries_json_='{}'
}

function add_for_duplicate {
  local -r _key_="$1"
  local -r _id_="$2"

  _entries_json_="$(
    jq -c --arg key "${_key_}" --arg id "${_id_}" '.[$key] |= .+ [ $id ]' <<<"${_entries_json_}"
    )"
}

function finalize_duplicate {
  _entries_json_="$(
    jq '[ to_entries[] | select( .value | length >1 ) ] | from_entries' <<<"${_entries_json_}"
    )"
}

Imaginons le code suivant :

init_duplicate

add_for_duplicate 'k1' 'v1-1'
add_for_duplicate 'k1' 'v1-2'
add_for_duplicate 'k2' 'v1-2'
add_for_duplicate 'k2' 'v2-2'
add_for_duplicate 'k3' 'v3-1'

jq '.' <<<"${_entries_json_}"

Le résultat intermédiaire sera :

{
  "k1": [ "v1-1", "v1-2" ],
  "k2": [ "v2-1", "v2-2" ],
  "k3": [ "v3-1" ]
}

Ensuite pour obtenir que les doubles, on peut faire :

finalize_duplicate

jq '.' <<<"${_entries_json_}"

Et voilà :

{
  "k1": [ "v1-1", "v1-2" ],
  "k2": [ "v1-2", "v2-2" ]
}

ඏ

Utilisation de la mémoire

Cette solution est assez gourmande en mĂ©moire et en CPU, mais il est trĂšs facile de l’adapter et de stocker le rĂ©sultat dans un fichier (au dĂ©triment du temps d’exĂ©cution, bien Ă©videment).

Le principal intĂ©rĂȘt de cette solution Ă©tant qu’elle est assez gĂ©nĂ©rique et s’adapte Ă  presque tous les cas.


ඏ

Références

኿


OĂč sont stockĂ©es les polices de caractĂšres sous Linux Mint ?

Sous Linux, les polices sont stockées dans différents répertoires, les plus communs sont :

  • /usr/share/fonts
  • /usr/local/share/fonts
  • ~/.fonts

Techniquement, vous pouvez mettre vos nouvelles polices dans n’importe lequel de ces dossiers, on peut cependant affiner un peu cela en respectant les normes et les conventions.

Par exemple, sous Linux Mint, les polices True Type Format sont classées un dossier spécifique :

  • /usr/share/fonts/truetype

et les polices pour l’utilisateur courant se trouve :

  • ~/.local/share/fonts

Beaucoup de logiciels embarquent leurs propres polices, c’est le cas de LibreOffice par exemple, les polices Ă©tant dessous /opt/libreoffice7.2/share/fonts, mais ce qui nous intĂ©resse c’est plutĂŽt les polices qui sont partagĂ©es :

Dessous /var/lib/flatpak/ il y a Ă©galement des polices, mais lĂ  encore, elles sont rĂ©servĂ©es. Il s’agit des applications au format flatpak, de mĂȘme dessous /snap/ pour les applications au format snap.

Voici d’autres dossiers notables :

  • /var/lib/dpkg/alternatives
  • /etc/alternatives

ඏ

OĂč mettre vos polices ?

Si vous utilisez l’outil de gestion des polices de caractùres de Linux Mint, lorsque vous cliquez sur le bouton installer, il utilisera le dossier : ~/.fonts

Cependant, si vous souhaitez que vos polices soient accessibles à tous les utilisateurs, il est plus pertinent de les copier dessous : /usr/local/share/fonts (ce qui nécessitera les droits administrateurs).


ඏ

Comment rechercher tous les fichiers contenant une police de caractÚre ?

Pour les plus curieux d’entre vous, je vous propose de partir Ă  l’exploration des polices de caractĂšres en dĂ©pliant le texte ci-dessous


  • Pour ceux qui souhaitent creuser


    Pour trouver toutes les fonts, vous pouvez utiliser:

    sudo find / -type f -iname '*.otf' -or -iname '*.ttf' 2>/dev/null
    

    -o ou -or sont de synonymes pour find.

    Notez qu’il existe d’autre type de ficher de police de caractùre, et certainement que votre systùme en supporte d’autre, vous adapterez a votre besoin


    On utilise sudo pour pouvoir atteindre tous les fichiers du disque, on recherche Ă  partir de la racine (/), on se limite aux fichiers (-type f) dont le nom fini par « .otf » (-iname '*.otf') ou (-or) par « .ttf » (-iname '*.ttf') et on masque les erreurs (2>/dev/null). Les erreurs Ă©tant dans ce cas normal, find va se heurter Ă  des fichiers appartenant au systĂšme qu’il ne peut pas gĂ©rer.

    La liste risque déjà trÚs longue et comme le but est de ne connaßtre que le dossier, on peut réduire considérablement les résultats comme suit :

    sudo find / -type f -iname '*.otf' -or -iname '*.ttf' -exec dirname {} \; 2>/dev/null | sort | uniq
    

    Il est possible d’accĂ©lĂ©rer un peu l’affichage, en partant du principe que la sortie de la commande find sera dĂ©jĂ  triĂ©e :

    sudo find / -type f -iname '*.otf' -or -iname '*.ttf' -exec dirname {} \; 2>/dev/null | uniq
    

    Cette recherche risque d’ĂȘtre lente, puisqu’elle va examiner l’ensemble du disque dur. Soit vous aller vous faire un cafĂ©, soit il faut essayer de limiter raisonnablement son pĂ©rimĂštre.

    sudo find / -type d \( -path '/cdrom' \
    -o -path '/lost+found' \
    -o -path '/tmp' \
    -o -path '/run' \
    -o -path '/proc' \
    -o -path '/media' \
    -o -path '/usr/share/fonts' \
    -o -path '/usr/local/share/fonts' \
    -o -path '/var/lib/flatpak' \
    -o -path '/mnt/data/home/claude/sources' \) \
    -prune -or -type f -iname '*.otf' -or -iname '*.ttf' -exec dirname {} \; 2>/dev/null | uniq
    

    Les dossiers exclus :

    • /cdrom – A priori, on ne veut pas explorer un Ă©ventuel CD,
    • /lost+found – Dossier systĂšme sans intĂ©rĂȘt ici,
    • /tmp – Dossier temporaire, les police-de-caractĂšre Ă©ventuelles ne rĂ©sistent pas Ă  un redĂ©marrage,
    • /run – Dossier systĂšme sans intĂ©rĂȘt ici,
    • /proc – Dossier systĂšme sans intĂ©rĂȘt ici,
    • /media – A priori, on ne veut pas rechercher sur d’éventuels points de montages,
    • /usr/share/fonts – On sait dĂ©jĂ  qu’il y a des fonts ici,
    • /usr/local/share/fonts – On sait dĂ©jĂ  qu’il y a des fonts ici,
    • /var/lib/flatpak – Les fonts prĂ©sentes dans ce dossier sont gĂ©rĂ©es par flatpak,
    • /mnt/data/home/claude/sources – Et vous pouvez ajouter d’éventuels dossiers perso


    On peut vouloirs chercher des polices en double, je vous propose pour cela de faire quelque chose du type :

    sudo find / -type d \( -path '/cdrom' \
    -o -path '/lost+found' \
    -o -path '/tmp' \
    -o -path '/run' \
    -o -path '/proc' \
    -o -path '/media' \
    -o -path '/mnt/data/home/claude/sources' \) \
    -prune -or -type f -iname '*.otf' -or -iname '*.ttf' \
    -exec sha512sum {} \; | sort >liste-police-de-caracteres.txt
    

    Pour examiner le résultat, qui sera assez long à produire, je vous conseille de mettre le résultat dans un fichier (ici liste-police-de-caracteres.txt).

    Les fichiers ayant le mĂȘme code ont le mĂȘme contenu.

    function show_duplicates {
      local -r file="$1"
    
      local last_key=
      local last_tail=
      local first_match='true'
    
      sort -t, -k1,1 "${file}" | while IFS=' ' read key tail ; do
        if [ "${key}" = "${last_key}" ] ; then
          if [ "${first_match}" = 'true' ] ; then
            echo "${last_key} ${last_tail}"
            first_match='false'
          fi
          echo "${key} ${tail}"
        else
          first_match='true'
        fi
        last_key="${key}"
        last_tail="${tail}"
      done
    }
    
    show_duplicates 'liste-police-de-caracteres.txt' >'liste-police-de-caracteres-en-double.txt'
    

    Une solution basée sur le format JSON me semble plus exploitable, mais je laisse le code intermédiaire à des fins de documentation.

    function show_duplicates_json {
      local -r file="$1"
    
      local last_key=
      local last_tail=
      local first_match='true'
      local json='{}'
    
      while IFS=' ' read key tail ; do
        if [ "${key}" = "${last_key}" ] ; then
          if [ "${first_match}" = 'true' ] ; then
            echo "${last_key} ${last_tail}" >&2
            json="$( jq -c --arg file "${last_tail}" ".[\"$last_key\"] |= .+ [ \$file ]" <<<"${json}" )"
            first_match='false'
          fi
          echo "${key} ${tail}" >&2
          json="$( jq -c --arg file "${tail}" ".[\"$key\"] |= .+ [ \$file ]" <<<"${json}" )"
        else
          first_match='true'
        fi
        last_key="${key}"
        last_tail="${tail}"
      done < <( sort -t, -k1,1 "${file}" )
    
      jq . <<<"${json}"
    }
    
    show_duplicates_json 'liste-police-de-caracteres.txt' >'liste-police-de-caracteres-en-double.json'
    

    Le contenu de ce fichier risque de vous faire peur. Vous constaterez qu'il y a beaucoup de polices de caractùres en double sur machine



ඏ

Références

኿


1 / Navigation / 3 ⋙ 108

Les anciens billets sont Ă©galement disponibles dans les archives.

â„č 2006 - 2021 | 🏠 Retour Ă  l'accueil du domaine | 🏡 Retour Ă  l'accueil du blog