{"id":416,"date":"2026-10-14T06:11:06","date_gmt":"2026-10-14T06:11:06","guid":{"rendered":"http:\/\/www.scmgalaxy.com\/tutorials\/2015\/08\/12\/gsh-run-linux-commands-on-many-other-linux-server-at-once\/"},"modified":"2026-10-14T06:11:06","modified_gmt":"2026-10-14T06:11:06","slug":"gsh-run-linux-commands-on-many-other-linux-server-at-once","status":"publish","type":"post","link":"https:\/\/www.devopsschool.com\/blog\/gsh-run-linux-commands-on-many-other-linux-server-at-once\/","title":{"rendered":"How to Use gsh to Run Linux Commands Across Multiple Servers"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\"><em>Originally published on 2015-08-12; fully revised and updated.<\/em><\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-3453 aligncenter\" src=\"http:\/\/www.scmgalaxy.com\/tutorials\/wp-content\/uploads\/2015\/08\/gsh-run-linux-commands.png\" alt=\"gsh-run-linux-commands\" width=\"600\" height=\"400\" srcset=\"https:\/\/www.devopsschool.com\/blog\/wp-content\/uploads\/2015\/08\/gsh-run-linux-commands.png 600w, https:\/\/www.devopsschool.com\/blog\/wp-content\/uploads\/2015\/08\/gsh-run-linux-commands-300x200.png 300w\" sizes=\"auto, (max-width: 600px) 100vw, 600px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>gsh<\/strong> (Group Shell) is a remote shell multiplexor: it runs commands across multiple machines at once while keeping remote shells interactive and persistent. This is useful for sysadmins and DevOps engineers who need to check state, gather data, or run repeatable operations across server fleets over SSH.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What gsh is and when to use it<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">In the original source, gsh is described as a pluggable Python implementation related to DSH (Distributed Shell). It requires remote shell access (commonly SSH) to each target host, then lets you select systems by tags\/macros and run one command across that set.<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Run the same read-only check on many servers (kernel, OS release, disk usage).<\/li><li>Target hosts by groups\/tags instead of manually listing hostnames.<\/li><li>Keep output grouped by host for quick triage.<\/li><\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">How host targeting works with \/etc\/ghosts<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">gsh uses <code>\/etc\/ghosts<\/code> to map hosts to tags. You then call gsh with a systems expression (macros\/tags) and a command.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css language-plaintext\"># <span class=\"hljs-selector-tag\">Machines<\/span>\n# <span class=\"hljs-selector-tag\">hostname<\/span> <span class=\"hljs-selector-tag\">OS-Version<\/span> <span class=\"hljs-selector-tag\">Hardware<\/span> <span class=\"hljs-selector-tag\">OS<\/span> <span class=\"hljs-selector-tag\">cp<\/span> <span class=\"hljs-selector-tag\">security<\/span>\n<span class=\"hljs-selector-tag\">linuxbrigade<\/span><span class=\"hljs-selector-class\">.com<\/span> <span class=\"hljs-selector-tag\">debian6<\/span> <span class=\"hljs-selector-tag\">baremetal<\/span> <span class=\"hljs-selector-tag\">linux<\/span> <span class=\"hljs-selector-tag\">plesk<\/span> <span class=\"hljs-selector-tag\">iptables<\/span>\n<span class=\"hljs-selector-tag\">linuxbrigade<\/span><span class=\"hljs-selector-class\">.com<\/span> <span class=\"hljs-selector-tag\">centos5<\/span> <span class=\"hljs-selector-tag\">vps<\/span> <span class=\"hljs-selector-tag\">linux<\/span> <span class=\"hljs-selector-tag\">cpanel<\/span> <span class=\"hljs-selector-tag\">csfcluster<\/span>\n<span class=\"hljs-selector-tag\">linuxbrigade<\/span><span class=\"hljs-selector-class\">.com<\/span> <span class=\"hljs-selector-tag\">debian7<\/span> <span class=\"hljs-selector-tag\">baremetal<\/span> <span class=\"hljs-selector-tag\">linux<\/span> <span class=\"hljs-selector-tag\">plesk<\/span> <span class=\"hljs-selector-tag\">iptables<\/span>\n<span class=\"hljs-selector-tag\">linuxbrigade<\/span><span class=\"hljs-selector-class\">.com<\/span> <span class=\"hljs-selector-tag\">centos6<\/span> <span class=\"hljs-selector-tag\">vps<\/span> <span class=\"hljs-selector-tag\">linux<\/span> <span class=\"hljs-selector-tag\">cpanel<\/span> <span class=\"hljs-selector-tag\">csfcluster<\/span>\n<span class=\"hljs-selector-tag\">linuxbrigade<\/span><span class=\"hljs-selector-class\">.com<\/span> <span class=\"hljs-selector-tag\">centos6<\/span> <span class=\"hljs-selector-tag\">vps<\/span> <span class=\"hljs-selector-tag\">linux<\/span> <span class=\"hljs-selector-tag\">cpanel<\/span> <span class=\"hljs-selector-tag\">csfcluster<\/span>\n<span class=\"hljs-selector-tag\">linuxbrigade<\/span><span class=\"hljs-selector-class\">.com<\/span> <span class=\"hljs-selector-tag\">centos6<\/span> <span class=\"hljs-selector-tag\">vps<\/span> <span class=\"hljs-selector-tag\">linux<\/span> <span class=\"hljs-selector-tag\">nocp<\/span> <span class=\"hljs-selector-tag\">denyhosts<\/span>\n<span class=\"hljs-selector-tag\">linuxbrigade<\/span><span class=\"hljs-selector-class\">.com<\/span> <span class=\"hljs-selector-tag\">debian6<\/span> <span class=\"hljs-selector-tag\">baremetal<\/span> <span class=\"hljs-selector-tag\">linux<\/span> <span class=\"hljs-selector-tag\">plesk<\/span> <span class=\"hljs-selector-tag\">iptables<\/span>\n<span class=\"hljs-selector-tag\">linuxbrigade<\/span><span class=\"hljs-selector-class\">.com<\/span> <span class=\"hljs-selector-tag\">centos6<\/span> <span class=\"hljs-selector-tag\">baremetal<\/span> <span class=\"hljs-selector-tag\">linux<\/span> <span class=\"hljs-selector-tag\">cpanel<\/span> <span class=\"hljs-selector-tag\">csf<\/span>\n<span class=\"hljs-selector-tag\">linuxbrigade<\/span><span class=\"hljs-selector-class\">.com<\/span> <span class=\"hljs-selector-tag\">centos5<\/span> <span class=\"hljs-selector-tag\">vps<\/span> <span class=\"hljs-selector-tag\">linux<\/span> <span class=\"hljs-selector-tag\">cpanel<\/span> <span class=\"hljs-selector-tag\">csf<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">The original article shows expressions like <code>cpanel+vps<\/code> and <code>web-RHEL4<\/code> for combining\/splitting groups. Exact behavior depends on your <code>ghosts(1)<\/code> macro rules and local configuration.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Execution workflow<\/h2>\n\n\n\n<pre class=\"mermaid\">\nflowchart TD\n    A[Set up SSH access to hosts] --> B[Define hosts and tags in etc ghosts]\n    B --> C[Run gsh with systems expression and command]\n    C --> D[gsh opens remote shells]\n    D --> E[Command runs on selected hosts]\n    E --> F[Output is returned per host]\n    F --> G[Review results and rerun as needed]\n<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Command syntax and option reference<\/h2>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css language-bash\"><span class=\"hljs-selector-tag\">gsh<\/span> <span class=\"hljs-selector-attr\">&#91;OPTIONS]<\/span> <span class=\"hljs-selector-tag\">SYSTEMS<\/span> <span class=\"hljs-selector-tag\">CMD<\/span>...<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">From the source: <code>SYSTEMS<\/code> is a combination of ghost macros, and <code>CMD<\/code> is the command to run remotely.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Option<\/th><th>Purpose<\/th><th>Typical use<\/th><\/tr><\/thead><tbody><tr><td><code>-h<\/code>, <code>--help<\/code><\/td><td>Display help<\/td><td>Check available flags on your installed version<\/td><\/tr><tr><td><code>-d<\/code>, <code>--debug<\/code><\/td><td>Enable execution debugging reports<\/td><td>Troubleshoot host matching or SSH execution<\/td><\/tr><tr><td><code>--no-host-prefix<\/code><\/td><td>Do not prefix output lines with hostname<\/td><td>Use only when host identity is not needed in output<\/td><\/tr><tr><td><code>-s<\/code>, <code>--show-commands<\/code><\/td><td>Show command before output report<\/td><td>Improve auditability of what was executed<\/td><\/tr><tr><td><code>-n<\/code>, <code>--open-stdin<\/code><\/td><td>Keep stdin open while running<\/td><td>Interactive scenarios (use carefully)<\/td><\/tr><tr><td><code>-l<\/code>, <code>--user USER<\/code><\/td><td>SSH as a specific user<\/td><td>Run as an ops account instead of current local user<\/td><\/tr><tr><td><code>-r<\/code>, <code>--run-locally<\/code><\/td><td>Run command locally, replacing <code>$host<\/code> with host<\/td><td>Template-like local command generation<\/td><\/tr><tr><td><code>-o<\/code>, <code>--self-remote<\/code><\/td><td>Run locally instead of SSH for local host<\/td><td>Avoid SSH to self when local host is in target set<\/td><\/tr><tr><td><code>-V<\/code>, <code>--version<\/code><\/td><td>Show version and exit<\/td><td>Validate binary version during troubleshooting<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Practical command examples<\/h2>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php language-bash\"><span class=\"hljs-comment\"># Example from the original post<\/span>\ngsh linux <span class=\"hljs-string\">\"cat \/etc\/redhat-release; uname -r\"<\/span>\n\n<span class=\"hljs-comment\"># Show command before output for better traceability<\/span>\ngsh -s linux <span class=\"hljs-string\">\"uptime\"<\/span>\n\n<span class=\"hljs-comment\"># Run as a specific user<\/span>\ngsh -l root linux <span class=\"hljs-string\">\"df -h \/\"<\/span>\n\n<span class=\"hljs-comment\"># Example tag expressions from the original post<\/span>\ngsh cpanel+vps <span class=\"hljs-string\">\"hostname\"<\/span>\ngsh web-RHEL4 <span class=\"hljs-string\">\"uname -a\"<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h2 class=\"wp-block-heading\">Command pattern comparison<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Pattern<\/th><th>Example<\/th><th>When to use<\/th><\/tr><\/thead><tbody><tr><td>Single tag\/group<\/td><td><code>gsh linux \"uptime\"<\/code><\/td><td>Operate on one broad fleet segment<\/td><\/tr><tr><td>Combined tags<\/td><td><code>gsh cpanel+vps \"hostname\"<\/code><\/td><td>Narrow to hosts that match combined criteria<\/td><\/tr><tr><td>Split\/exclusion style<\/td><td><code>gsh web-RHEL4 \"uname -a\"<\/code><\/td><td>Target one set while removing another (per ghosts rules)<\/td><\/tr><tr><td>Explicit remote user<\/td><td><code>gsh -l root linux \"df -h \/\"<\/code><\/td><td>Use controlled privileged account context<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">References<\/h2>\n\n\n\n<ul class=\"wp-block-list\"><li><a href=\"http:\/\/www.linuxbrigade.com\/run-the-same-command-on-many-linux-servers-at-once\/\" target=\"_blank\" rel=\"noopener\">http:\/\/www.linuxbrigade.com\/run-the-same-command-on-many-linux-servers-at-once\/<\/a><\/li><li><a href=\"http:\/\/linux.die.net\/man\/1\/gsh\" target=\"_blank\" rel=\"noopener\">http:\/\/linux.die.net\/man\/1\/gsh<\/a><\/li><li><a href=\"https:\/\/github.com\/gmjosack\/gsh\" target=\"_blank\" rel=\"noopener\">https:\/\/github.com\/gmjosack\/gsh<\/a><\/li><li><a href=\"http:\/\/outflux.net\/unix\/software\/gsh\/\" target=\"_blank\" rel=\"noopener\">http:\/\/outflux.net\/unix\/software\/gsh\/<\/a><\/li><li><a href=\"http:\/\/outflux.net\/unix\/software\/gsh\/gsh.html\" target=\"_blank\" rel=\"noopener\">http:\/\/outflux.net\/unix\/software\/gsh\/gsh.html<\/a><\/li><\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Best practices and common pitfalls<\/h2>\n\n\n\n<ul class=\"wp-block-list\"><li>Set up SSH keys before using gsh at scale to avoid repeated password prompts.<\/li><li>Start with read-only commands first (for example, <code>uptime<\/code>, <code>uname<\/code>, <code>cat<\/code>) before making changes.<\/li><li>Keep host prefixes enabled for easier debugging across many targets.<\/li><li>Validate group\/tag expressions on a small subset before broad execution.<\/li><li>Review <code>ghosts(1)<\/code> and <code>gsh --help<\/code> on your installed version, because option details can vary.<\/li><\/ul>\n","protected":false},"excerpt":{"rendered":"<p>gsh (Group Shell) lets you execute one command across many Linux hosts from a single terminal. This guide explains host grouping with \/etc\/ghosts, core options, and practical command patterns.<\/p>\n","protected":false},"author":1,"featured_media":3453,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_joinchat":[],"footnotes":""},"categories":[4957],"tags":[378,1670,1665,460,1666,1667,1672,1671,1669,1668,399],"class_list":["post-416","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-linux","tag-commands","tag-execute","tag-gsh","tag-linux","tag-linux-command","tag-linux-server","tag-multiple-linux-server","tag-multiple-servers","tag-once","tag-run","tag-server"],"_links":{"self":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/416","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/comments?post=416"}],"version-history":[{"count":3,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/416\/revisions"}],"predecessor-version":[{"id":79289,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/416\/revisions\/79289"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/media\/3453"}],"wp:attachment":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/media?parent=416"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/categories?post=416"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/tags?post=416"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}