diff --git a/CHANGELOG.md b/CHANGELOG.md
index 58e989ac82917413cc2f31a692d27f98637f74c2..fc1222b0673c3247dd9abfb383ca498484cdb3c5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,10 @@
 CHANGELOG
 =========
 
+6.1.0
+-----
+- Ajout des commandes shell de concaténation de fichiers PDF avec Ghostscript ou QPDF.
+
 6.0.1
 -----
 - Ajout d'une fonction statique afin de simplifier le code de création de PDF dans les applications. 
diff --git a/composer.json b/composer.json
index 913da851af7d619891c8f4eda757678ab3d3e396..3242b3df65656148b927733a98bb02d169d732a4 100644
--- a/composer.json
+++ b/composer.json
@@ -5,7 +5,8 @@
     "php": "^8.0",
     "mpdf/mpdf": "^8.0",
     "laminas/laminas-view": "^2.22",
-    "laminas/laminas-dependency-plugin": "^2.1"
+    "laminas/laminas-dependency-plugin": "^2.1",
+    "unicaen/shell": "^1.0"
   },
   "require-dev": {
     "laminas/laminas-test": "^4.0",
diff --git a/config/module.config.php b/config/module.config.php
index a27f36787d27049ea3dde6be30ec5c77762913fd..bfc2340a9999f69bcedc316b8c21b6ec3eea38a9 100644
--- a/config/module.config.php
+++ b/config/module.config.php
@@ -2,32 +2,53 @@
 
 namespace UnicaenPdf;
 
+use UnicaenPdf\Command\PdfMergeShellCommandGs;
+use UnicaenPdf\Command\PdfMergeShellCommandQpdf;
+use UnicaenPdf\Options\ModuleOptions;
+use UnicaenPdf\Options\ModuleOptionsFactory;
+
 return [
-    'router'          => [
+    'unicaen-pdf' => [
+
+    ],
+
+    'unicaen-shell' => [
+        'commands' => [
+            PdfMergeShellCommandGs::class => [
+                'executable' => '/usr/bin/gs',
+            ],
+            PdfMergeShellCommandQpdf::class => [
+                'executable' => '/usr/bin/qpdf',
+            ],
+        ],
+    ],
+
+    'router' => [
         'routes' => [
         ],
     ],
-    'console'         => [
-        'router'       => [
+    'console' => [
+        'router' => [
             'routes' => [
             ],
         ],
     ],
     'service_manager' => [
-        'factories'          => [
+        'factories' => [
+            ModuleOptions::class => ModuleOptionsFactory::class,
         ],
     ],
-    'view_helpers'    => [
-        'aliases'      => [
+    'view_helpers' => [
+        'aliases' => [
         ],
-        'factories'    => [
+        'factories' => [
         ],
     ],
-    'controllers'     => [
-        'factories'    => [
+    'controllers' => [
+        'factories' => [
         ],
     ],
-    'navigation'   => [
+    'navigation' => [
         'default' => [
         ],
     ],
diff --git a/src/UnicaenPdf/Command/PdfMergeShellCommandAwareTrait.php b/src/UnicaenPdf/Command/PdfMergeShellCommandAwareTrait.php
new file mode 100644
index 0000000000000000000000000000000000000000..7908d8f394650b6050cc785ce9195850b10d40bc
--- /dev/null
+++ b/src/UnicaenPdf/Command/PdfMergeShellCommandAwareTrait.php
@@ -0,0 +1,13 @@
+<?php
+
+namespace UnicaenPdf\Command;
+
+trait PdfMergeShellCommandAwareTrait
+{
+    protected PdfMergeShellCommandInterface $pdfMergeShellCommand;
+
+    public function setPdfMergeShellCommand(PdfMergeShellCommandInterface $pdfMergeShellCommand): void
+    {
+        $this->pdfMergeShellCommand = $pdfMergeShellCommand;
+    }
+}
\ No newline at end of file
diff --git a/src/UnicaenPdf/Command/PdfMergeShellCommandGs.php b/src/UnicaenPdf/Command/PdfMergeShellCommandGs.php
new file mode 100644
index 0000000000000000000000000000000000000000..f031d0f37b291aceb2ebf1831bd15bb46c07729e
--- /dev/null
+++ b/src/UnicaenPdf/Command/PdfMergeShellCommandGs.php
@@ -0,0 +1,42 @@
+<?php
+
+namespace UnicaenPdf\Command;
+
+use UnicaenPdf\Command\PdfMergeShellCommandInterface;
+use UnicaenShell\Command\ShellCommand;
+
+/**
+ * Commande de concaténation de N fichiers PDF.
+ *
+ * Version utilisant 'ghostscript'.
+ */
+final class PdfMergeShellCommandGs extends ShellCommand implements PdfMergeShellCommandInterface
+{
+    protected string $noCompressionOption = '-dColorConversionStrategy=/LeaveColorUnchanged -dDownsampleMonoImages=false -dDownsampleGrayImages=false -dDownsampleColorImages=false -dAutoFilterColorImages=false -dAutoFilterGrayImages=false -dColorImageFilter=/FlateEncode -dGrayImageFilter=/FlateEncode';
+
+    /**
+     * @return string
+     */
+    public function getName(): string
+    {
+        return 'PdfMergeShellCommandGs';
+    }
+
+    public function checkRequirements(): void
+    {
+        $this->assertExecutableExists();
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function generateCommandLine()
+    {
+        $command = $this->executable . ' ' . $this->noCompressionOption;
+        $command .=
+            ' -dNOPAUSE -sDEVICE=pdfwrite -sOUTPUTFILE=' . $this->outputFilePath .
+            ' -dBATCH ' . implode(' ', $this->inputFilesPaths);
+
+        $this->commandLine = $command;
+    }
+}
\ No newline at end of file
diff --git a/src/UnicaenPdf/Command/PdfMergeShellCommandInterface.php b/src/UnicaenPdf/Command/PdfMergeShellCommandInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..5049cb7a4781fb086e72228985b2f723206ee7fc
--- /dev/null
+++ b/src/UnicaenPdf/Command/PdfMergeShellCommandInterface.php
@@ -0,0 +1,12 @@
+<?php
+
+namespace UnicaenPdf\Command;
+
+use UnicaenShell\Command\ShellCommandInterface;
+
+/**
+ * Commande de concaténation de fichiers PDF.
+ */
+interface PdfMergeShellCommandInterface extends ShellCommandInterface
+{
+}
\ No newline at end of file
diff --git a/src/UnicaenPdf/Command/PdfMergeShellCommandQpdf.php b/src/UnicaenPdf/Command/PdfMergeShellCommandQpdf.php
new file mode 100644
index 0000000000000000000000000000000000000000..4142babe7fb51bd4b56569878e2279018e41d8a6
--- /dev/null
+++ b/src/UnicaenPdf/Command/PdfMergeShellCommandQpdf.php
@@ -0,0 +1,37 @@
+<?php
+
+namespace UnicaenPdf\Command;
+
+use UnicaenPdf\Command\PdfMergeShellCommandInterface;
+use UnicaenShell\Command\ShellCommand;
+
+/**
+ * Commande de concaténation de N fichiers PDF.
+ *
+ * Version utilisant 'qpdf'.
+ */
+final class PdfMergeShellCommandQpdf extends ShellCommand implements PdfMergeShellCommandInterface
+{
+    public function getName(): string
+    {
+        return 'MergeShellCommandQpdf';
+    }
+
+    public function checkRequirements(): void
+    {
+        $this->assertExecutableExists();
+    }
+
+    public function generateCommandLine()
+    {
+        // Commande de fusion (cf. https://qpdf.readthedocs.io/en/10.5/cli.html#page-selection-options)
+        $command = $this->executable .
+            sprintf(' --warning-exit-0 %s --pages . %s -- %s',
+                array_shift($this->inputFilesPaths),
+                implode(' ', $this->inputFilesPaths),
+                $this->outputFilePath
+            );
+
+        $this->commandLine = $command;
+    }
+}
\ No newline at end of file
diff --git a/src/UnicaenPdf/Options/ModuleOptions.php b/src/UnicaenPdf/Options/ModuleOptions.php
new file mode 100644
index 0000000000000000000000000000000000000000..5d08f301edab70de0c6823415f8e00e5412a33b8
--- /dev/null
+++ b/src/UnicaenPdf/Options/ModuleOptions.php
@@ -0,0 +1,13 @@
+<?php
+
+namespace UnicaenPdf\Options;
+
+/**
+ * Classe encapsulant les options de fonctionnement du module.
+ *
+ * @author Bertrand GAUTHIER <bertrand.gauthier@unicaen.fr>
+ */
+class ModuleOptions
+{
+
+}
\ No newline at end of file
diff --git a/src/UnicaenPdf/Options/ModuleOptionsAwareTrait.php b/src/UnicaenPdf/Options/ModuleOptionsAwareTrait.php
new file mode 100644
index 0000000000000000000000000000000000000000..75a0ac8550ccefb96df3cf08fc630494ecf0c944
--- /dev/null
+++ b/src/UnicaenPdf/Options/ModuleOptionsAwareTrait.php
@@ -0,0 +1,13 @@
+<?php
+
+namespace UnicaenPdf\Options;
+
+trait ModuleOptionsAwareTrait
+{
+    protected ModuleOptions $moduleOptions;
+
+    public function setModuleOptions(ModuleOptions $moduleOptions): void
+    {
+        $this->moduleOptions = $moduleOptions;
+    }
+}
\ No newline at end of file
diff --git a/src/UnicaenPdf/Options/ModuleOptionsFactory.php b/src/UnicaenPdf/Options/ModuleOptionsFactory.php
new file mode 100644
index 0000000000000000000000000000000000000000..f664785ba19f2f71f186e6f530d102a47fa5279d
--- /dev/null
+++ b/src/UnicaenPdf/Options/ModuleOptionsFactory.php
@@ -0,0 +1,16 @@
+<?php
+
+namespace UnicaenPdf\Options;
+
+use Interop\Container\ContainerInterface;
+
+/**
+ * @author Unicaen
+ */
+class ModuleOptionsFactory
+{
+    public function __invoke(ContainerInterface $container): ModuleOptions
+    {
+        return new ModuleOptions();
+    }
+}
\ No newline at end of file