diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index b7f7c22..fcfa47e 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -1,6 +1,7 @@
 name: "Build"
 on:
   push:
+    paths-ignore: [ '*.md' ]
     branches:
       - master
 
diff --git a/.github/workflows/pull-request-verification.yml b/.github/workflows/pull-request-verification.yml
index 801c7ce..9d95fc3 100644
--- a/.github/workflows/pull-request-verification.yml
+++ b/.github/workflows/pull-request-verification.yml
@@ -1,6 +1,7 @@
 name: "Pull Request Verification"
 on:
   pull_request:
+    paths-ignore: [ '*.md' ]
     branches:
       - master
       - develop
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3d1001e..31e166b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,8 @@
 # Changelog
 
+## v2.9.0
+- [Add list-files: csv format](https://github.com/dorny/paths-filter/pull/68)
+
 ## v2.8.0
 - [Add count output variable](https://github.com/dorny/paths-filter/pull/65)
 - [Fix log grouping of changes](https://github.com/dorny/paths-filter/pull/61)
diff --git a/README.md b/README.md
index 780574a..9ecce9b 100644
--- a/README.md
+++ b/README.md
@@ -66,13 +66,13 @@ For more scenarios see [examples](#examples) section.
 
 
 # What's New
+- Add `list-files: csv` format
 - Configure matrix job to run for each folder with changes using `changes` output
 - Improved listing of matching files with `list-files: shell` and `list-files: escape` options
 - Support local changes
 - Fixed retrieval of all changes via Github API when there are 100+ changes
 - Paths expressions are now evaluated using [picomatch](https://github.com/micromatch/picomatch) library
 - Support workflows triggered by any event
-- Fixed compatibility with older (<2.23) versions of git
 
 For more information see [CHANGELOG](https://github.com/dorny/paths-filter/blob/master/CHANGELOG.md)
 
@@ -122,6 +122,8 @@ For more information see [CHANGELOG](https://github.com/dorny/paths-filter/blob/
 
     # Enables listing of files matching the filter:
     #   'none'  - Disables listing of matching files (default).
+    #   'csv'   - Coma separated list of filenames.
+    #             If needed it uses double quotes to wrap filename with unsafe characters.
     #   'json'  - Matching files paths are formatted as JSON array.
     #   'shell' - Space delimited list usable as command line argument list in Linux shell.
     #             If needed it uses single or double quotes to wrap filename with unsafe characters.
diff --git a/__tests__/csv-escape.test.ts b/__tests__/csv-escape.test.ts
new file mode 100644
index 0000000..f6dc6df
--- /dev/null
+++ b/__tests__/csv-escape.test.ts
@@ -0,0 +1,23 @@
+import {csvEscape} from '../src/list-format/csv-escape'
+
+describe('csvEscape() backslash escapes every character except subset of definitely safe characters', () => {
+  test('simple filename should not be modified', () => {
+    expect(csvEscape('file.txt')).toBe('file.txt')
+  })
+
+  test('directory separator should be preserved and not escaped', () => {
+    expect(csvEscape('path/to/file.txt')).toBe('path/to/file.txt')
+  })
+
+  test('filename with spaces should be quoted', () => {
+    expect(csvEscape('file with space')).toBe('"file with space"')
+  })
+
+  test('filename with "," should be quoted', () => {
+    expect(csvEscape('file, with coma')).toBe('"file, with coma"')
+  })
+
+  test('Double quote should be escaped by another double quote', () => {
+    expect(csvEscape('file " with double quote')).toBe('"file "" with double quote"')
+  })
+})
diff --git a/__tests__/shell-escape.test.ts b/__tests__/shell-escape.test.ts
index e706dfb..ece4c37 100644
--- a/__tests__/shell-escape.test.ts
+++ b/__tests__/shell-escape.test.ts
@@ -1,24 +1,24 @@
-import {escape, shellEscape} from '../src/shell-escape'
+import {backslashEscape, shellEscape} from '../src/list-format/shell-escape'
 
 describe('escape() backslash escapes every character except subset of definitely safe characters', () => {
   test('simple filename should not be modified', () => {
-    expect(escape('file.txt')).toBe('file.txt')
+    expect(backslashEscape('file.txt')).toBe('file.txt')
   })
 
   test('directory separator should be preserved and not escaped', () => {
-    expect(escape('path/to/file.txt')).toBe('path/to/file.txt')
+    expect(backslashEscape('path/to/file.txt')).toBe('path/to/file.txt')
   })
 
   test('spaces should be escaped with backslash', () => {
-    expect(escape('file with space')).toBe('file\\ with\\ space')
+    expect(backslashEscape('file with space')).toBe('file\\ with\\ space')
   })
 
   test('quotes should be escaped with backslash', () => {
-    expect(escape('file\'with quote"')).toBe('file\\\'with\\ quote\\"')
+    expect(backslashEscape('file\'with quote"')).toBe('file\\\'with\\ quote\\"')
   })
 
   test('$variables should be escaped', () => {
-    expect(escape('$var')).toBe('\\$var')
+    expect(backslashEscape('$var')).toBe('\\$var')
   })
 })
 
diff --git a/action.yml b/action.yml
index 41c15ba..894b114 100644
--- a/action.yml
+++ b/action.yml
@@ -22,6 +22,8 @@ inputs:
     description: |
       Enables listing of files matching the filter:
         'none'  - Disables listing of matching files (default).
+        'csv'   - Coma separated list of filenames.
+                  If needed it uses double quotes to wrap filename with unsafe characters.
         'json'  - Serialized as JSON array.
         'shell' - Space delimited list usable as command line argument list in linux shell.
                   If needed it uses single or double quotes to wrap filename with unsafe characters.
diff --git a/dist/index.js b/dist/index.js
index 35a3f9e..fcf0faa 100644
--- a/dist/index.js
+++ b/dist/index.js
@@ -4648,7 +4648,8 @@ const github = __importStar(__webpack_require__(469));
 const filter_1 = __webpack_require__(235);
 const file_1 = __webpack_require__(258);
 const git = __importStar(__webpack_require__(136));
-const shell_escape_1 = __webpack_require__(751);
+const shell_escape_1 = __webpack_require__(206);
+const csv_escape_1 = __webpack_require__(410);
 async function run() {
     try {
         const workingDirectory = core.getInput('working-directory', { required: false });
@@ -4825,10 +4826,12 @@ function exportResults(results, format) {
 function serializeExport(files, format) {
     const fileNames = files.map(file => file.filename);
     switch (format) {
+        case 'csv':
+            return fileNames.map(csv_escape_1.csvEscape).join(',');
         case 'json':
             return JSON.stringify(fileNames);
         case 'escape':
-            return fileNames.map(shell_escape_1.escape).join(' ');
+            return fileNames.map(shell_escape_1.backslashEscape).join(' ');
         case 'shell':
             return fileNames.map(shell_escape_1.shellEscape).join(' ');
         default:
@@ -4836,7 +4839,7 @@ function serializeExport(files, format) {
     }
 }
 function isExportFormat(value) {
-    return value === 'none' || value === 'shell' || value === 'json' || value === 'escape';
+    return ['none', 'csv', 'shell', 'json', 'escape'].includes(value);
 }
 run();
 
@@ -5028,6 +5031,43 @@ module.exports = {
 };
 
 
+/***/ }),
+
+/***/ 206:
+/***/ (function(__unusedmodule, exports) {
+
+"use strict";
+
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.shellEscape = exports.backslashEscape = void 0;
+// Backslash escape every character except small subset of definitely safe characters
+function backslashEscape(value) {
+    return value.replace(/([^a-zA-Z0-9,._+:@%/-])/gm, '\\$1');
+}
+exports.backslashEscape = backslashEscape;
+// Returns filename escaped for usage as shell argument.
+// Applies "human readable" approach with as few escaping applied as possible
+function shellEscape(value) {
+    if (value === '')
+        return value;
+    // Only safe characters
+    if (/^[a-zA-Z0-9,._+:@%/-]+$/m.test(value)) {
+        return value;
+    }
+    if (value.includes("'")) {
+        // Only safe characters, single quotes and white-spaces
+        if (/^[a-zA-Z0-9,._+:@%/'\s-]+$/m.test(value)) {
+            return `"${value}"`;
+        }
+        // Split by single quote and apply escaping recursively
+        return value.split("'").map(shellEscape).join("\\'");
+    }
+    // Contains some unsafe characters but no single quote
+    return `'${value}'`;
+}
+exports.shellEscape = shellEscape;
+
+
 /***/ }),
 
 /***/ 211:
@@ -8813,6 +8853,33 @@ function Octokit(plugins, options) {
 }
 
 
+/***/ }),
+
+/***/ 410:
+/***/ (function(__unusedmodule, exports) {
+
+"use strict";
+
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.csvEscape = void 0;
+// Returns filename escaped for CSV
+// Wraps file name into "..." only when it contains some potentially unsafe character
+function csvEscape(value) {
+    if (value === '')
+        return value;
+    // Only safe characters
+    if (/^[a-zA-Z0-9._+:@%/-]+$/m.test(value)) {
+        return value;
+    }
+    // https://tools.ietf.org/html/rfc4180
+    // If double-quotes are used to enclose fields, then a double-quote
+    // appearing inside a field must be escaped by preceding it with
+    // another double quote
+    return `"${value.replace(/"/g, '""')}"`;
+}
+exports.csvEscape = csvEscape;
+
+
 /***/ }),
 
 /***/ 413:
@@ -15225,43 +15292,6 @@ function sync (path, options) {
 
 module.exports = require("fs");
 
-/***/ }),
-
-/***/ 751:
-/***/ (function(__unusedmodule, exports) {
-
-"use strict";
-
-Object.defineProperty(exports, "__esModule", { value: true });
-exports.shellEscape = exports.escape = void 0;
-// Backslash escape every character except small subset of definitely safe characters
-function escape(value) {
-    return value.replace(/([^a-zA-Z0-9,._+:@%/-])/gm, '\\$1');
-}
-exports.escape = escape;
-// Returns filename escaped for usage as shell argument.
-// Applies "human readable" approach with as few escaping applied as possible
-function shellEscape(value) {
-    if (value === '')
-        return value;
-    // Only safe characters
-    if (/^[a-zA-Z0-9,._+:@%/-]+$/m.test(value)) {
-        return value;
-    }
-    if (value.includes("'")) {
-        // Only safe characters, single quotes and white-spaces
-        if (/^[a-zA-Z0-9,._+:@%/'\s-]+$/m.test(value)) {
-            return `"${value}"`;
-        }
-        // Split by single quote and apply escaping recursively
-        return value.split("'").map(shellEscape).join("\\'");
-    }
-    // Contains some unsafe characters but no single quote
-    return `'${value}'`;
-}
-exports.shellEscape = shellEscape;
-
-
 /***/ }),
 
 /***/ 753:
diff --git a/src/list-format/csv-escape.ts b/src/list-format/csv-escape.ts
new file mode 100644
index 0000000..262cf2d
--- /dev/null
+++ b/src/list-format/csv-escape.ts
@@ -0,0 +1,16 @@
+// Returns filename escaped for CSV
+// Wraps file name into "..." only when it contains some potentially unsafe character
+export function csvEscape(value: string): string {
+  if (value === '') return value
+
+  // Only safe characters
+  if (/^[a-zA-Z0-9._+:@%/-]+$/m.test(value)) {
+    return value
+  }
+
+  // https://tools.ietf.org/html/rfc4180
+  // If double-quotes are used to enclose fields, then a double-quote
+  // appearing inside a field must be escaped by preceding it with
+  // another double quote
+  return `"${value.replace(/"/g, '""')}"`
+}
diff --git a/src/shell-escape.ts b/src/list-format/shell-escape.ts
similarity index 93%
rename from src/shell-escape.ts
rename to src/list-format/shell-escape.ts
index 25bb940..1a3e3c9 100644
--- a/src/shell-escape.ts
+++ b/src/list-format/shell-escape.ts
@@ -1,5 +1,5 @@
 // Backslash escape every character except small subset of definitely safe characters
-export function escape(value: string): string {
+export function backslashEscape(value: string): string {
   return value.replace(/([^a-zA-Z0-9,._+:@%/-])/gm, '\\$1')
 }
 
diff --git a/src/main.ts b/src/main.ts
index 3e9522f..a54776f 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -6,9 +6,10 @@ import {Webhooks} from '@octokit/webhooks'
 import {Filter, FilterResults} from './filter'
 import {File, ChangeStatus} from './file'
 import * as git from './git'
-import {escape, shellEscape} from './shell-escape'
+import {backslashEscape, shellEscape} from './list-format/shell-escape'
+import {csvEscape} from './list-format/csv-escape'
 
-type ExportFormat = 'none' | 'json' | 'shell' | 'escape'
+type ExportFormat = 'none' | 'csv' | 'json' | 'shell' | 'escape'
 
 async function run(): Promise<void> {
   try {
@@ -210,10 +211,12 @@ function exportResults(results: FilterResults, format: ExportFormat): void {
 function serializeExport(files: File[], format: ExportFormat): string {
   const fileNames = files.map(file => file.filename)
   switch (format) {
+    case 'csv':
+      return fileNames.map(csvEscape).join(',')
     case 'json':
       return JSON.stringify(fileNames)
     case 'escape':
-      return fileNames.map(escape).join(' ')
+      return fileNames.map(backslashEscape).join(' ')
     case 'shell':
       return fileNames.map(shellEscape).join(' ')
     default:
@@ -222,7 +225,7 @@ function serializeExport(files: File[], format: ExportFormat): string {
 }
 
 function isExportFormat(value: string): value is ExportFormat {
-  return value === 'none' || value === 'shell' || value === 'json' || value === 'escape'
+  return ['none', 'csv', 'shell', 'json', 'escape'].includes(value)
 }
 
 run()