{"id":291,"date":"2026-10-13T09:32:26","date_gmt":"2026-10-13T09:32:26","guid":{"rendered":"http:\/\/www.scmgalaxy.com\/tutorials\/2010\/12\/10\/shell-script-parameters\/"},"modified":"2026-10-13T09:32:26","modified_gmt":"2026-10-13T09:32:26","slug":"shell-script-parameters","status":"publish","type":"post","link":"https:\/\/www.devopsschool.com\/blog\/shell-script-parameters\/","title":{"rendered":"Bash Shell Script Parameters: A Practical Reference for Positional and Special Variables"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\"><em>Originally published on 2010-12-10; fully revised and updated.<\/em><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This reference is for DevOps engineers writing Bash automation. You will learn how positional and special parameters work, how argument expansion differs between <code>$*<\/code> and <code>$@<\/code>, and how to handle script inputs safely. For historical context, see the <a href=\"https:\/\/www.devopsschool.com\/blog\/shell-script-parameters\/\">original post<\/a>.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"https:\/\/www.devopsschool.com\/blog\/wp-content\/uploads\/2010\/12\/shell-script-parameters.png\" alt=\"Shell script parameters reference\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Bash parameter types at a glance<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">In Bash, a parameter is any entity that stores a value. For day-to-day scripting, the most important categories are <strong>positional parameters<\/strong> (arguments passed to a script) and <strong>special parameters<\/strong> (shell-provided values such as exit code and process IDs).<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><strong>Positional parameters<\/strong>: <code>$0<\/code>, <code>$1<\/code> &#8230; <code>$9<\/code>, and <code>${10}<\/code> onward.<\/li><li><strong>Special parameters<\/strong>: <code>$#<\/code>, <code>$@<\/code>, <code>$*<\/code>, <code>$?<\/code>, <code>$$<\/code>, <code>$!<\/code>, <code>$-<\/code>, <code>$_<\/code>.<\/li><li><strong>Important<\/strong>: for argument numbers above 9, use braces (for example, <code>${10}<\/code>), not <code>$10<\/code>.<\/li><\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Quick reference for common Bash parameters<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Parameter<\/th><th>What it represents<\/th><th>Typical use<\/th><\/tr><\/thead><tbody><tr><td><code>$0<\/code><\/td><td>Script name as invoked (may include a path)<\/td><td>Usage\/help messages<\/td><\/tr><tr><td><code>$1<\/code> &#8230; <code>$9<\/code>, <code>${10}<\/code><\/td><td>Positional arguments<\/td><td>Read user input values<\/td><\/tr><tr><td><code>$#<\/code><\/td><td>Argument count<\/td><td>Validate required inputs<\/td><\/tr><tr><td><code>$*<\/code><\/td><td>All positional parameters<\/td><td>Aggregate argument handling<\/td><\/tr><tr><td><code>$@<\/code><\/td><td>All positional parameters<\/td><td>Forward arguments safely<\/td><\/tr><tr><td><code>$?<\/code><\/td><td>Exit status of last command<\/td><td>Error handling branches<\/td><\/tr><tr><td><code>$$<\/code><\/td><td>Current shell process ID<\/td><td>Logging and process correlation<\/td><\/tr><tr><td><code>$!<\/code><\/td><td>PID of most recent background job<\/td><td>Wait\/monitor background work<\/td><\/tr><tr><td><code>$-<\/code><\/td><td>Current shell option flags<\/td><td>Debugging shell mode state<\/td><\/tr><tr><td><code>$_<\/code><\/td><td>Last argument of previous command (context-dependent)<\/td><td>Occasional debugging<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">How parameters flow through a script<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A typical argument-handling flow validates count first, then processes inputs, and finally checks command status or background job IDs as needed.<\/p>\n\n\n\n<pre class=\"mermaid\">\nflowchart TD\n    A[Run script with arguments] --> B[Shell assigns script name and positional values]\n    B --> C[Read argument count]\n    C --> D{Enough arguments}\n    D -- no --> E[Print usage and exit]\n    D -- yes --> F[Process positional parameters]\n    F --> G[Optional set -- to replace values]\n    G --> H[Run commands and check exit status]\n    H --> I[Optionally read process ids]\n<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Example 1: Positional parameters for arithmetic input<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">This Bash script accepts two integer arguments, validates them, and performs arithmetic. Bash arithmetic uses integer math here, so division is integer division.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php language-bash\"><span class=\"hljs-comment\">#!\/usr\/bin\/env bash<\/span>\n<span class=\"hljs-keyword\">if<\/span> &#91; <span class=\"hljs-string\">\"$#\"<\/span> -lt <span class=\"hljs-number\">2<\/span> ]; then\n  <span class=\"hljs-keyword\">echo<\/span> <span class=\"hljs-string\">\"Usage: $0 num1 num2\"<\/span>\n  <span class=\"hljs-keyword\">exit<\/span> <span class=\"hljs-number\">1<\/span>\nfi\n\na=$<span class=\"hljs-number\">1<\/span>\nb=$<span class=\"hljs-number\">2<\/span>\n\n<span class=\"hljs-keyword\">if<\/span> &#91; <span class=\"hljs-string\">\"$b\"<\/span> -eq <span class=\"hljs-number\">0<\/span> ]; then\n  <span class=\"hljs-keyword\">echo<\/span> <span class=\"hljs-string\">\"Error: num2 must not be zero for division\"<\/span>\n  <span class=\"hljs-keyword\">exit<\/span> <span class=\"hljs-number\">1<\/span>\nfi\n\nprintf <span class=\"hljs-string\">'$1=%s\\n'<\/span> <span class=\"hljs-string\">\"$a\"<\/span>\nprintf <span class=\"hljs-string\">'$2=%s\\n'<\/span> <span class=\"hljs-string\">\"$b\"<\/span>\n<span class=\"hljs-keyword\">echo<\/span> <span class=\"hljs-string\">\"Addition=$((a + b))\"<\/span>\n<span class=\"hljs-keyword\">echo<\/span> <span class=\"hljs-string\">\"Subtraction=$((a - b))\"<\/span>\n<span class=\"hljs-keyword\">echo<\/span> <span class=\"hljs-string\">\"Multiplication=$((a * b))\"<\/span>\n<span class=\"hljs-keyword\">echo<\/span> <span class=\"hljs-string\">\"Division=$((a \/ b))\"<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><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<pre class=\"wp-block-code\"><span><code class=\"hljs language-bash\">chmod +x arithmetic.sh\n.\/arithmetic.sh 12 10\n\n$1=12\n$2=10\nAddition=22\nSubtraction=2\nMultiplication=120\nDivision=1<\/code><\/span><\/pre>\n\n\n<h2 class=\"wp-block-heading\">Example 2: Set, replace, and clear positional parameters with set &#8212;<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The <code>set<\/code> builtin can overwrite positional parameters inside the current shell context. Using <code>set --<\/code> with no following values clears them.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php language-bash\"><span class=\"hljs-comment\">#!\/usr\/bin\/env bash<\/span>\nprintf <span class=\"hljs-string\">'Initial: $1=%s $2=%s $3=%s\\n'<\/span> <span class=\"hljs-string\">\"$1\"<\/span> <span class=\"hljs-string\">\"$2\"<\/span> <span class=\"hljs-string\">\"$3\"<\/span>\n\nset -- First Second Third\nprintf <span class=\"hljs-string\">'After set words: $1=%s $2=%s $3=%s\\n'<\/span> <span class=\"hljs-string\">\"$1\"<\/span> <span class=\"hljs-string\">\"$2\"<\/span> <span class=\"hljs-string\">\"$3\"<\/span>\n\nset -- -f -s -t\nprintf <span class=\"hljs-string\">'After set -- with hyphen values: $1=%s $2=%s $3=%s\\n'<\/span> <span class=\"hljs-string\">\"$1\"<\/span> <span class=\"hljs-string\">\"$2\"<\/span> <span class=\"hljs-string\">\"$3\"<\/span>\n\nset --\nprintf <span class=\"hljs-string\">'After clear: $1=%s $2=%s $3=%s\\n'<\/span> <span class=\"hljs-string\">\"$1\"<\/span> <span class=\"hljs-string\">\"$2\"<\/span> <span class=\"hljs-string\">\"$3\"<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><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<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript language-bash\">.\/positional.sh <span class=\"hljs-number\">12<\/span> <span class=\"hljs-number\">10<\/span>\n<span class=\"hljs-attr\">Initial<\/span>: $<span class=\"hljs-number\">1<\/span>=<span class=\"hljs-number\">12<\/span> $<span class=\"hljs-number\">2<\/span>=<span class=\"hljs-number\">10<\/span> $<span class=\"hljs-number\">3<\/span>=\nAfter <span class=\"hljs-keyword\">set<\/span> words: $1=First $2=Second $3=Third\nAfter <span class=\"hljs-keyword\">set<\/span> -- with hyphen values: $1=-f $2=-s $3=-t\nAfter clear: $1= $2= $3=<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h2 class=\"wp-block-heading\">Example 3: The difference between &#8220;$*&#8221; and &#8220;$@&#8221;<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The most important difference appears in quoted form. Quoted <code>\"$*\"<\/code> becomes a single word, while quoted <code>\"$@\"<\/code> preserves each argument as a separate word.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Form<\/th><th>Behavior<\/th><th>When to use<\/th><\/tr><\/thead><tbody><tr><td><code>\"$*\"<\/code><\/td><td>One string containing all arguments, joined by first character of IFS<\/td><td>When you intentionally need one combined value<\/td><\/tr><tr><td><code>\"$@\"<\/code><\/td><td>Each argument remains a separate word<\/td><td>Preferred for forwarding arguments to another command<\/td><\/tr><tr><td><code>$*<\/code> (unquoted)<\/td><td>Subject to word splitting and pathname expansion<\/td><td>Usually avoid in robust scripts<\/td><\/tr><tr><td><code>$@<\/code> (unquoted)<\/td><td>Also subject to splitting\/expansion<\/td><td>Usually avoid in robust scripts<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php language-bash\"><span class=\"hljs-comment\">#!\/usr\/bin\/env bash<\/span>\nIFS=<span class=\"hljs-string\">'-'<\/span>\ncnt=<span class=\"hljs-number\">1<\/span>\n\n<span class=\"hljs-keyword\">echo<\/span> <span class=\"hljs-string\">'Values of \"$*\":'<\/span>\n<span class=\"hljs-keyword\">for<\/span> arg in <span class=\"hljs-string\">\"$*\"<\/span>; <span class=\"hljs-keyword\">do<\/span>\n  <span class=\"hljs-keyword\">echo<\/span> <span class=\"hljs-string\">\"Arg #$cnt = $arg\"<\/span>\n  ((cnt+=<span class=\"hljs-number\">1<\/span>))\ndone\n\ncnt=<span class=\"hljs-number\">1<\/span>\n<span class=\"hljs-keyword\">echo<\/span> <span class=\"hljs-string\">'Values of \"$@\":'<\/span>\n<span class=\"hljs-keyword\">for<\/span> arg in <span class=\"hljs-string\">\"$@\"<\/span>; <span class=\"hljs-keyword\">do<\/span>\n  <span class=\"hljs-keyword\">echo<\/span> <span class=\"hljs-string\">\"Arg #$cnt = $arg\"<\/span>\n  ((cnt+=<span class=\"hljs-number\">1<\/span>))\ndone<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><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<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php language-bash\">.\/expan.sh <span class=\"hljs-string\">\"This is\"<\/span> <span class=\"hljs-number\">2<\/span> <span class=\"hljs-number\">3<\/span>\nValues of <span class=\"hljs-string\">\"$*\"<\/span>:\nArg <span class=\"hljs-comment\">#1 = This is-2-3<\/span>\nValues of <span class=\"hljs-string\">\"$@\"<\/span>:\nArg <span class=\"hljs-comment\">#1 = This is<\/span>\nArg <span class=\"hljs-comment\">#2 = 2<\/span>\nArg <span class=\"hljs-comment\">#3 = 3<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><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\">Process and status parameters: $$, $!, $?, $-, $_<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">These special parameters are useful for process control and troubleshooting in automation scripts.<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><code>$$<\/code>: PID of the current shell process.<\/li><li><code>$!<\/code>: PID of the most recently started background process.<\/li><li><code>$?<\/code>: exit code of the previous command.<\/li><li><code>$-<\/code>: currently enabled shell option flags.<\/li><li><code>$_<\/code>: last argument of the previous command; useful sometimes, but context-sensitive.<\/li><\/ul>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php language-bash\"><span class=\"hljs-comment\">#!\/usr\/bin\/env bash<\/span>\n<span class=\"hljs-keyword\">echo<\/span> <span class=\"hljs-string\">\"Shell PID: $$\"<\/span>\n\nsleep <span class=\"hljs-number\">30<\/span> &amp;\nbg_pid=$!\n<span class=\"hljs-keyword\">echo<\/span> <span class=\"hljs-string\">\"Most recent background PID: $bg_pid\"<\/span>\n\nwait <span class=\"hljs-string\">\"$bg_pid\"<\/span>\n<span class=\"hljs-keyword\">echo<\/span> <span class=\"hljs-string\">\"Exit status of wait: $?\"<\/span>\n\n<span class=\"hljs-keyword\">echo<\/span> <span class=\"hljs-string\">\"Shell option flags: $-\"<\/span>\n<span class=\"hljs-keyword\">echo<\/span> <span class=\"hljs-string\">\"alpha beta gamma\"<\/span>\n<span class=\"hljs-keyword\">echo<\/span> <span class=\"hljs-string\">\"Previous command last argument via $_: $_\"<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><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\">Common pitfalls and best practices<\/h2>\n\n\n\n<ul class=\"wp-block-list\"><li>Validate argument count early with <code>$#<\/code> and fail fast with a clear usage message.<\/li><li>Use <code>\"$@\"<\/code> when forwarding arguments; avoid unquoted <code>$*<\/code> and <code>$@<\/code> in production scripts.<\/li><li>Use <code>${10}<\/code>, <code>${11}<\/code>, and so on for argument numbers above 9.<\/li><li>Guard arithmetic operations (especially division) with input checks.<\/li><li>Use <code>set --<\/code> intentionally; it replaces the current positional parameters in the active shell context.<\/li><li>Treat <code>$_<\/code> as convenience, not core control logic, because behavior can vary by context.<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">If you consistently combine argument validation, careful quoting, and exit-status checks, your shell scripts become much safer for CI\/CD and operations automation.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Learn how Bash passes arguments to scripts and how special parameters like $#, $@, $*, $$, and $? behave. This updated reference includes workflow diagrams, comparison tables, and production-friendly examples.<\/p>\n","protected":false},"author":1,"featured_media":4336,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_joinchat":[],"footnotes":""},"categories":[454],"tags":[137,4034,4033,4036,4035,4031,278,138,4038,3046,4037,4032,4040,4041,4043,4039,4042],"class_list":["post-291","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-shell-script","tag-bash","tag-bash-positional-parameter","tag-bash-shell","tag-bash-shell-script-parameters","tag-bash-special-parameters","tag-parameters","tag-script","tag-shell","tag-shell-parameter-values","tag-shell-script","tag-shell-script-arguments-example","tag-shell-script-parameters","tag-shell-script-parameters-guide","tag-shell-script-parameters-instructions","tag-shell-script-parameters-reference","tag-shell-script-pass-parameter","tag-understand-shell-script-parameters"],"_links":{"self":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/291","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=291"}],"version-history":[{"count":3,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/291\/revisions"}],"predecessor-version":[{"id":79127,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/291\/revisions\/79127"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/media\/4336"}],"wp:attachment":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/media?parent=291"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/categories?post=291"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/tags?post=291"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}