---
title: "Comment diviser un jeu de données en lots avec Python"
slug: how-to-split-datasets
date: 2026-02-17T09:07:43+00:00
modified: 2026-02-17T09:07:45+00:00
permalink: https://brightdata.fr/blog/donnees-web/how-to-split-datasets
type: blog
---

[ Blog ](https://brightdata.fr/blog "Blog") / [Données Web](https://brightdata.fr/blog/donnees-web)







 [Données Web](https://brightdata.fr/blog/donnees-web)

# Comment diviser un jeu de données en lots avec Python

Découvrez des techniques pour diviser des jeux de données en lots dans Python, améliorer l’efficacité de la mémoire, la vitesse de traitement et l’entraînement des modèles.

 15 min de lecture





 [ ![Antonello Zanini](https://media.brightdata.fr/2022/12/Antonello-Zanini-2-50x50.jpg) ](https://brightdata.com/blog/authors/antonello-zanini)

 [Antonello Zanini

Technical Writer

 ](https://brightdata.com/blog/authors/antonello-zanini)





 ![How to Split Dataset Into Batches blog image](https://media.brightdata.fr/2024/11/How-to-Split-Dataset-Into-Batches-blog-image.svg)





Dans ce guide, vous apprendrez :

- La définition du lot
- Pourquoi traiter les jeux de données par lots
- Comment diviser un ensemble de données en lots dans Python
- L’approche de l’option `map()` `par lots` pour les jeux de données

C’est parti !

## <a></a>Qu’est-ce qu’un lot ?

Dans le monde du ML et du traitement des données, un lot n’est rien d’autre qu’un sous-ensemble d’un [jeu de données](/blog/web-data/what-is-a-dataset). Les lots sont généralement utilisés pour traiter efficacement de grands volumes de données. Au lieu de traiter un jeu de données entier en une seule fois, les données sont divisées en petits morceaux, également appelés *lots*. Chaque lot peut être traité indépendamment, ce qui permet de réduire l’utilisation de la mémoire et d’améliorer l’efficacité des calculs.

Par exemple, supposons que vous disposiez d’un échantillon de données au format CSV :

```none
id,nom,âge,score
1,John,28,85
2,Jane,34,90
3,Bob,25,72
4,Alice,30,88
5,Charlie,29,91
6,David,35,79
7,Eve,22,95
8,Frank,31,82
9,Grace,27,86
10,Hannah,26,80

```

Un lot des jeux de données ci-dessus est :

```none
6, David, 35, 79
7, Eve, 22, 95
8, Frank, 31, 82
9, Grace, 27, 86
10, Hannah, 26, 80

```

Ce lot découpe l’ensemble de jeux de données original de la ligne 5 à la ligne 10.

## <a></a>Avantages de l’utilisation du traitement d’un jeu de données par lots

Supposons que vous disposiez d’un jeu de données que vous avez créé à l’aide de certaines techniques [de sourcing de données](/blog/web-data/data-sourcing). Si vous n’êtes pas familier avec ce processus, suivez notre guide sur [la création d’un jeu de données](/blog/web-data/how-to-create-datasets).

Pourquoi voudriez-vous traiter cet ensemble de données par lots ? Parce que cela présente les avantages suivants :

- **Efficacité de la mémoire**: travaillez avec des portions plus petites et plus faciles à gérer à la fois, au lieu de charger l’ensemble du jeu de données dans la mémoire.
- **Traitement plus rapide**: le traitement par lots peut être parallélisé, ce qui réduit le temps nécessaire au traitement de grands jeux de données.
- **Meilleur apprentissage pour les modèles ML**: facilite l’apprentissage des modèles de machine learning en mettant à jour les poids de manière incrémentielle, ce qui peut entraîner une convergence plus stable et plus rapide.
- **Meilleure évolutivité**: facilite l’adaptation de votre traitement à des jeux de données volumineux qui ne peuvent pas tenir en mémoire en une seule fois.

## <a></a>Comment diviser un jeu de données en lots : les 5 meilleures approches

Avant d’explorer les meilleures méthodes Python pour diviser un jeu de données en lots, nous devons identifier certains critères d’évaluation de ces approches. Voici une liste pertinente d’aspects à prendre en compte :

- **Mise en œuvre**: un extrait de code montrant comment utiliser l’approche dans un exemple simple.
- **Scénarios**: les situations réelles dans lesquelles l’approche de division des jeux de données est applicable.
- **Entrée**: les types de fichiers de jeux de données et les structures de données pris en charge par la stratégie de fractionnement.
- **Avantages**: les avantages offerts par l’approche.
- **Inconvénients**: les limites ou les inconvénients de la méthode.

Il est temps de les analyser un par un !

### <a></a>Approche n° 1 : découpage de tableaux

[Le découpage de tableaux](https://www.freecodecamp.org/news/python-slicing-how-to-slice-an-array/) est une méthode simple pour diviser un jeu de données en lots plus petits et plus faciles à gérer. L’idée est de diviser un jeu de données (représenté par une liste, un tableau ou une autre séquence) en morceaux en le découpant.

👨‍💻 **Mise en œuvre**:

```none
def create_batches(data, batch_size):
    return [data[i:i + batch_size] for i in range(0, len(data), batch_size)]

# exemple d'utilisation
data = list(range(1, 51))  # exemple d'ensemble de données
batches = create_batches(data, batch_size=5)

print(batches)

# résultat : [[1, 2, 3, 4, 5], ..., [46, 47, 48, 49, 50]]

```

🎯 **Scénarios**:

- Tâches de prétraitement des données où les limitations de mémoire sont minimes
- Tâches de traitement de données en parallèle nécessitant des blocs de mémoire gérables
- Traitement simple par lots dans les pipelines de données

🔠 **Entrée**:

- Listes, tableaux et tuples en Python.
- Tableaux Numpy
- Données CSV, chargées en mémoire sous forme de liste de lignes
- Pandas DataFrames, s’ils sont convertis en listes ou tableaux

👍 **Avantages**:

- Simple et facile à mettre en œuvre
- Ne nécessite pas de bibliothèques externes
- Permet un contrôle direct sur la taille des lots

👎 **Inconvénients**:

- Limité par la mémoire disponible
- Ne prend pas en charge les jeux de données extrêmement volumineux ou les structures de données complexes
- Nécessite une logique personnalisée pour [le brassage des données](https://medium.com/@sanjay_dutta/what-is-shuffling-the-data-a-guide-for-students-0f874572baf6)

### <a></a>Approche n° 2 : générateurs

[Les générateurs Python](https://wiki.python.org/moin/Generators) vous permettent de diviser un jeu de données en lots en produisant un lot à la fois. Si vous n’êtes pas familier avec ce mécanisme, un générateur est un type spécial de fonction qui se comporte comme un itérateur. Au lieu de renvoyer directement les données, il utilise le mot-clé `yield` pour produire un objet itérateur. Cela permet d’accéder aux lots de manière séquentielle à l’aide d’une boucle `for` ou de la fonction [`next()`](https://docs.python.org/3/library/functions.html#next).

**👨‍💻 Implémentation**:

```none
def data_generator(data, batch_size):
    for i in range(0, len(data), batch_size):
        yield data[i:i + batch_size]

# exemple d'utilisation
data = list(range(1, 51))  # exemple d'ensemble de données
for batch in data_generator(data, batch_size=5):
    print(batch)

# sortie :
# [1, 2, 3, 4, 5]
# ...
# [46, 47, 48, 49, 50]

```

🎯 **Scénarios**:

- Traitement par lots dans les pipelines de données
- [Tâches](https://www.ibm.com/topics/data-augmentation) de prétraitement et [d’augmentation](https://www.ibm.com/topics/data-augmentation) de données à grande échelle
- Du traitement par lots simple au traitement par lots complexe dans les pipelines de données

🔠 **Entrée**:

- Listes, tableaux et tuples
- Tableaux NumPy
- Jeux de données basés sur des fichiers où le chargement de chaque lot à partir du disque est possible

👍 **Avantages**:

- Peut traiter de grands jeux de données sans les charger entièrement en mémoire
- Configuration minimale et mise en œuvre facile
- Permet un chargement contrôlé et à la demande des données

👎 **Inconvénients**:

- Limité par l’ordre des données, sauf si un remaniement supplémentaire est mis en œuvre
- Moins efficace pour les tailles de lots dynamiques ou variables
- Peut ne pas être la meilleure solution pour le traitement parallèle, en particulier pour les opérations multithread

### <a></a>Approche n° 3 : PyTorch DataLoader

La classe [`DataLoader`](https://pytorch.org/docs/stable/data.html#torch.utils.data.DataLoader) de [PyTorch](https://pytorch.org/) vous aide à diviser efficacement les jeux de données en lots gérables. En tant que structure de données spécialisée dans le traitement des jeux de données, elle offre également des fonctionnalités utiles telles que le mélange et le chargement parallèle des données.

Notez que `DataLoader` fonctionne avec [`TensorDataset`](https://pytorch.org/docs/stable/data.html#torch.utils.data.TensorDataset), une autre structure de données PyTorch destinée à représenter un jeu de données. Plus précisément, un `TensorDataset` accepte deux arguments :

1. `inps`: les données d’entrée, généralement sous la forme d’un [`tenseur`](https://pytorch.org/docs/stable/tensors.html#torch.Tensor).
2. `tgts`: les étiquettes ou valeurs cibles, généralement sous forme de tenseur, correspondant aux données d’entrée.

`TensorDataset` associe les `données` et `la cible`, qui peuvent ensuite être chargées par `DataLoader` pour le traitement par lots et l’entraînement.

👨‍💻 **Implémentation**:

```none
from torch.utils.data import DataLoader, TensorDataset
import torch

# données pour définir un ensemble de données simple
inputs = torch.arange(1, 51).float().reshape(-1, 1)  # un ensemble de données tensoriel 1D (entrée)
targets = inputs ** 2  # carré des valeurs d'entrée (simulant une tâche de régression)

# création d'un TensorDataset et d'un DataLoader
dataset = TensorDataset(inputs, targets)
dataloader = DataLoader(dataset, batch_size=5, shuffle=True)

# itérer à travers DataLoader
for batch in dataloader:
    print(batch)

# exemple de sortie :
# [tensor([[46.],
#         [42.],
#         [25.],
#         [10.],
#         [34.]]), tensor([[2116.],
#         [1764.],
#         [ 625.],
#         [ 100.],
#         [1156.]])]
# ...
# [tensor([[21.],
#         [ 9.],
#         [ 2.],
#         [38.],
#         [44.]]), tensor([[ 441.],
#         [  81.],
#         [   4.],
#         [1444.],
#         [1936.]])]

```

🎯 **Scénarios**:

- Entraînement et test de modèles d’apprentissage automatique dans PyTorch
- Mélange des données pour obtenir des lots d’entraînement non biaisés
- Traitement de données à grande échelle pour des tâches d’apprentissage profond

🔠 **Entrée**:

- Jeux de données personnalisés chargés dans PyTorch `TensorDatasets`
- Données tabulaires et tableaux numériques au format `Tensor`

👍 **Avantages**:

- Optimisé pour les grands jeux de données avec traitement par lots et brassage
- Prend en charge le chargement parallèle des données, accélérant la récupération par lots
- Fonctionne de manière transparente avec les modèles PyTorch et les boucles d’entraînement
- Compatible avec le traitement GPU

👎 **Inconvénients**:

- Nécessite PyTorch
- Nécessite la conversion des données en tenseurs.
- N’est pas idéal pour les tâches de traitement par lots non liées au ML

### <a></a>Approche n° 4 : méthode `batch()` de TensorFlow

La méthode [`batch()`](https://www.tensorflow.org/api_docs/python/tf/data/Dataset#batch) de TensorFlow `Dataset` permet de diviser les Jeux de données en lots. Cette méthode divise les Jeux de données en morceaux plus petits, avec des fonctionnalités telles que la parallélisation, le contrôle de l’ordre de traitement et la dénomination.

En tant que bibliothèque d’apprentissage automatique, TensorFlow offre également des fonctionnalités supplémentaires telles que le mélange, la répétition et la prélecture.

👨‍💻 **Implémentation**:

```none
import tensorflow as tf

# créer un exemple de jeu de données
inputs = tf.range(1, 51, dtype=tf.float32)  # un jeu de données tensoriel 1D (entrées)
targets = inputs ** 2  # carré des valeurs d'entrée (simulant une tâche de régression)

# convertir les entrées et les cibles en tf.data.Dataset
inputs_dataset = tf.data.Dataset.from_tensor_slices(inputs)
targets_dataset = tf.data.Dataset.from_tensor_slices(targets)

# créer un ensemble de données en compressant les entrées et les cibles ensemble
ensemble_de_données = tf.data.Dataset.zip((ensemble_de_données_entrées, ensemble_de_données_cibles))

# produire un ensemble de données par lots
ensemble_de_données_par_lots = ensemble_de_données.batch(batch_size=5)

pour lot dans ensemble_de_données_par_lots :
    imprimer(lot)

# sortie :
# (<tf.Tensor: shape=(5,), dtype=float32, numpy=array([1., 2., 3., 4., 5.], dtype=float32)>, <tf.Tensor: shape=(5,), dtype=float32, numpy=array([ 1.,  4.,  9., 16., 25.], dtype=float32)>)
# ...
# (<tf.Tensor: shape=(5,), dtype=float32, numpy=array([46., 47., 48., 49., 50.], dtype=float32)>, <tf.Tensor: shape=(5,), dtype=float32, numpy=array([2116., 2209., 2304., 2401., 2500.], dtype=float32)>)

```

🎯 **Scénarios**:

- Entraînement et test de modèles d’apprentissage automatique dans PyTorch
- Mélange des données pour obtenir des lots d’entraînement non biaisés
- Traitement de données à grande échelle pour des tâches d’apprentissage profond

🔠 **Entrée**:

- Objets TensorFlow `tf.data.Dataset`
- Tableaux NumPy (qui peuvent être convertis en `Dataset`)
- [Fichiers TFRecord](https://www.tensorflow.org/tutorials/load_data/tfrecord), un format de fichier binaire spécial couramment utilisé pour stocker de grands jeux de données dans TensorFlow

👍 **Avantages**:

- Optimisé pour une utilisation efficace de la mémoire
- S’intègre parfaitement à l’écosystème TensorFlow pour l’entraînement et l’évaluation des modèles
- Prend en charge le shuffling, le préchargement et d’autres fonctionnalités utiles
- Prend en charge une grande variété de formats de données, y compris les images, le texte et les données structurées

👎 **Inconvénients**:

- Nécessite TensorFlow
- Pour les jeux de données plus complexes, une configuration supplémentaire peut être nécessaire pour formater et prétraiter correctement les données
- Peut entraîner une surcharge pour le traitement par lots de petits jeux de données

### <a></a>Approche n° 5 : format HDF5

[HDF5](https://www.hdfgroup.org/solutions/hdf5/) est un format de données largement adopté pour la gestion de grands jeux de données, en particulier lorsqu’il s’agit de structures de données hiérarchiques. Il permet de diviser un grand jeu de données en morceaux et de les stocker efficacement.

La bibliothèque Python [`h5py`](https://docs.h5py.org/en/stable/) fournit des outils pour travailler avec des fichiers HDF5 et les charger en tant que structures de données NumPy. Cela ouvre la voie au traitement par lots des Jeux de données en accédant à des tranches ou segments spécifiques de données à la demande.

👨‍💻 **Mise en œuvre**:

```none
import h5py
import numpy as np

# charger et traiter par lots les données du fichier HDF5
def load_data_in_batches(batch_size=10):
    # ouvrir un fichier HDF5
    with h5py.File("dataset.h5", "r") as f:
        inputs = f["input"]
        targets = f["target"]

        # regrouper les données par lots à l'aide d'un itérateur à partir du disque
        for i in range(0, len(data), batch_size):
            yield inputs[i:i+batch_size], targets[i:i+batch_size]

# itérer à travers les lots
for batch_data, batch_target in load_data_in_batches():
    print("Lot d'entrée :", batch_input)
    print("Lot cible :", batch_target)

# sortie :
# Lot d'entrée : [[ 1]
#  [ 2]
#  [ 3]
#  [ 4]
#  [ 5]
#  [ 6]
#  [ 7]
#  [ 8]
#  [ 9]
#  [10]]
# Lot cible : [[  1]
#  [  4]
#  [  9]
#  [ 16]
#  [ 25]
#  [ 36]
#  [ 49]
#  [ 64]
#  [ 81]
#  [100]]
#  ...
# Lot d'entrée : [[41]
#  [42]
#  [43]
#  [44]
#  [45]
#  [46]
#  [47]
#  [48]
#  [49]
#  [50]]
# Lot cible : [[1681]
#  [1764]
#  [1849]
#  [1936]
#  [2026]
#  [2116]
#  [2209]
#  [2304]
#  [2401]
#  [2500]]

```

🎯 **Scénarios**:

- Idéal pour les très grands jeux de données qui ne peuvent pas être chargés entièrement en mémoire
- Utile lorsque vous travaillez avec des données multidimensionnelles
- Convient pour stocker et récupérer des données à partir d’un disque dans un format compressé efficace pour les tâches d’apprentissage automatique

🔠 **Entrée**:

- Fichiers HDF5

👍 **Avantages**:

- HDF5 prend en charge la compression et le découpage des données, ce qui réduit les besoins en stockage pour les grands jeux de données
- Permet un accès aléatoire efficace à certaines parties de grands jeux de données sans tout charger en mémoire
- Peut stocker plusieurs jeux de données dans un seul fichier, ce qui le rend particulièrement adapté aux jeux de données complexes.
- Prise en charge par de nombreuses bibliothèques scientifiques, notamment NumPy, TensorFlow et PyTorch

👎 **Inconvénients**:

- Nécessite une configuration supplémentaire et une connaissance du format HDF5.
- Pour disposer d’une API complète permettant de traiter les fichiers HDF5, il faut recourir à la bibliothèque `h5py`
- Tous les jeux de données ne sont pas disponibles au format HDF5

## <a></a>Autres solutions

Bien que les approches présentées ci-dessus comptent parmi les meilleures façons de diviser un jeu de données en lots, il existe également d’autres solutions viables.

Une autre solution possible consiste à utiliser [la bibliothèque `de Jeux de données` Hugging Face](https://huggingface.co/docs/datasets/en/index). Celle-ci vous fournit tout ce dont vous avez besoin pour appliquer des transformations à l’ensemble d’un jeu de données tout en le traitant par lots. En définissant `batched=True`, vous pouvez définir des transformations au niveau des lots sans avoir à découper manuellement le jeu de données, comme dans l’exemple ci-dessous :

```none
from Jeux de données import load_dataset

# charger un exemple de jeu de données
dataset = load_dataset("imdb", split="train")

# définir une fonction de traitement par lots
def process_batch(batch):
    # tâche de tokenisation simple
    return {"tokens": [text.split() for text in batch["text"]]}

# appliquer le traitement par lots
batched_dataset = dataset.map(process_batch, batched=True, batch_size=32)

```

L’option `dataset` `map()` `batched=True` est idéale lorsque vous devez appliquer des transformations, telles que la tokenisation, par lots.

Notez que l’utilisation `de map(batched=True)` est très efficace pour le traitement par lots, car elle minimise l’utilisation de la mémoire et accélère les workflows de transformation. Cette méthode est particulièrement utile pour traiter des données textuelles et tabulaires dans le cadre de tâches de NLP et d’apprentissage automatique.

## <a></a>Conclusion

Dans ce guide sur la manière de diviser un jeu de données en lots, vous avez découvert les meilleures approches, bibliothèques et solutions pour découper des données en Python. L’objectif est de diviser un jeu de données volumineux en parties plus faciles à gérer afin de simplifier et d’accélérer le traitement des données.

Quelle que soit l’approche choisie, toutes les solutions ci-dessus dépendent de l’accès à un jeu de données contenant les informations recherchées. Si certains jeux de données sont librement accessibles pour la recherche scientifique, ce n’est pas toujours le cas.

Si vous avez besoin d’ensembles de données couvrant des catégories allant de la finance aux données cinématographiques, consultez la plateforme [Dataset Marketplace de Bright Data](/products/datasets). Celle-ci donne accès à des centaines de jeux de données provenant de sites populaires, classés dans les catégories suivantes :

- [Jeux de données commerciales](/products/datasets/business): données provenant de sources clés telles que LinkedIn, CrunchBase, Owler et Indeed.
- [Jeux de données sur le commerce électronique](/products/datasets/ecommerce): données provenant d’Amazon, Walmart, Target, Zara, Zalando, Asos et bien d’autres.
- [Jeux de données immobilières](/products/datasets/real-estate): données provenant de sites web tels que Zillow, MLS, etc.
- [Jeux de données sur les réseaux sociaux](/products/datasets/social-media): données provenant de Facebook, Instagram, YouTube et Reddit.
- [Jeux de données financières](/products/datasets/financial): données provenant de Yahoo Finance, Market Watch, Investopedia, etc.

Si ces options prédéfinies ne répondent pas à vos besoins, envisagez nos[services de collecte de données personnalisés](/products/datasets).

De plus, Bright Data propose une large gamme d’outils de scraping puissants, notamment [des API Web Scraper](/products/web-scraper) et [Navigateur de scraping](/products/scraping-browser).

Créez gratuitement un compte Bright Data pour commencer à explorer ces Jeux de données !



Contacter ventesEssai gratuit![google social icon](/wp-content/themes/brightdata/assets/images/ic_google.svg)









 Table des matières







Dedicated Scraper APIs &amp; No-Code Scrapers

Over 1000 scrapers for all popular domains. Simplify your web scraping.

[See pricing](/pricing/web-scraper "See pricing")

Just want data? Skip scraping.

Hundreds of ready-to-use datasets from all popular domains.

[See pricing](/pricing/datasets "See pricing")







 [ ](https://news.ycombinator.com/submitlink?t=Comment+diviser+un+jeu+de+donn%C3%A9es+en+lots+avec+Python&u=https://brightdata.fr/blog/donnees-web/how-to-split-datasets) [ ](https://www.linkedin.com/shareArticle?mini=true&title=Comment+diviser+un+jeu+de+donn%C3%A9es+en+lots+avec+Python&url=https://brightdata.fr/blog/donnees-web/how-to-split-datasets) [ ](http://www.reddit.com/submit?title=Comment+diviser+un+jeu+de+donn%C3%A9es+en+lots+avec+Python&url=https://brightdata.fr/blog/donnees-web/how-to-split-datasets)







##  Vous pourriez aussi être intéressé par

 [ ![OpenHuman with Bright Data](https://media.brightdata.fr/2026/09/OpenHuman-with-Bright-Data.png) ](https://brightdata.fr/blog/ai/openhuman-with-bright-data "Accès Web Prêt pour la Production dans OpenHuman via le CLI Bright Data")

 [AI



 ![Antonello Zanini](https://media.brightdata.fr/2022/12/Antonello-Zanini-2-50x50.jpg)

Antonello Zanini

Technical Writer





### Accès Web Prêt pour la Production dans OpenHuman via le CLI Bright Data

Intégrez le CLI Bright Data avec OpenHuman pour permettre un accès web prêt pour la production et la collecte de données pour les agents IA.



 09-Sep-2026

 14 min de lecture

 ](https://brightdata.fr/blog/ai/openhuman-with-bright-data)

 [ ![Multimodal Web Scraping with MiniMax](https://media.brightdata.fr/2026/09/Multimodal-Web-Scraping-with-MiniMax.png) ](https://brightdata.fr/blog/donnees-web/multimodal-web-scraping-with-minimax "Scraping Web Multimodal avec MiniMax")

 [Données Web



 ![Antonello Zanini](https://media.brightdata.fr/2022/12/Antonello-Zanini-2-50x50.jpg)

Antonello Zanini

Technical Writer





### Scraping Web Multimodal avec MiniMax

Associez Bright Data Web Unlocker avec la vision MiniMax M3 pour extraire des données structurées à partir d’images et de captures d’écran de pages web.



 09-Sep-2026

 5 min de lecture

 ](https://brightdata.fr/blog/donnees-web/multimodal-web-scraping-with-minimax)

 [ ![The 10 Best CLI Tools for Codex in 2026](https://media.brightdata.fr/2026/08/The-10-Best-CLI-Tools-for-Codex-in-2026.png) ](https://brightdata.fr/blog/ai/best-cli-tools-for-codex "Les 10 meilleurs outils CLI pour Codex en 2026 – Testés & Classés")

 [AI



 ![Daniel Shashko](https://media.brightdata.fr/2022/04/Daniel-Shashko-2-50x50.png)

Daniel Shashko

Web Data &amp; AI Expert





### Les 10 meilleurs outils CLI pour Codex en 2026 – Testés &amp; Classés

Les 10 outils CLI qui rendent Codex plus rapide et plus capable, en commençant par le Bright Data CLI pour un accès web réel depuis l’intérieur du sandbox.



 06-Sep-2026

 24 min de lecture

 ](https://brightdata.fr/blog/ai/best-cli-tools-for-codex)
