scripting:obsolete

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
Last revision Both sides next revision
scripting:obsolete [2015/08/07 03:22]
bill_thomson
scripting:obsolete [2019/01/22 23:37]
bignose Correct formatting markup.
Line 22: Line 22:
 |''​`COMMANDS`'' ​ |''​$(COMMANDS)'' ​ |This is the older Bourne-compatible form of the [[syntax:​expansion:​cmdsubst | command substitution]]. Both the ''​`COMMANDS`''​ and ''​$(COMMANDS)''​ syntaxes are specified by POSIX, but the latter is _greatly_ preferred, though the former is unfortunately still very prevalent in scripts. New-style command substitutions are widely implemented by every modern shell (and then some). The only reason for using backticks is for compatibility with a real Bourne shell (like Heirloom). Backtick command substitutions require special escaping when nested, and examples found in the wild are improperly quoted more often than not. See: //​[[http://​mywiki.wooledge.org/​BashFAQ/​082 | Why is $(...) preferred over `...` (backticks)?​]]//​.| |''​`COMMANDS`'' ​ |''​$(COMMANDS)'' ​ |This is the older Bourne-compatible form of the [[syntax:​expansion:​cmdsubst | command substitution]]. Both the ''​`COMMANDS`''​ and ''​$(COMMANDS)''​ syntaxes are specified by POSIX, but the latter is _greatly_ preferred, though the former is unfortunately still very prevalent in scripts. New-style command substitutions are widely implemented by every modern shell (and then some). The only reason for using backticks is for compatibility with a real Bourne shell (like Heirloom). Backtick command substitutions require special escaping when nested, and examples found in the wild are improperly quoted more often than not. See: //​[[http://​mywiki.wooledge.org/​BashFAQ/​082 | Why is $(...) preferred over `...` (backticks)?​]]//​.|
 |''​[\ EXPRESSION\ ]''​\ and\ ''​test\ EXPRESSION'' ​ |''<​nowiki>​[[</​nowiki>​\ EXPRESSION\ <​nowiki>​]]</​nowiki>'' ​ |''​test''​ and ''​[''​ are the Bourne/​POSIX commands for evaluating test expressions (they are almost identical, and ''​[''​ is somewhat more common). The expressions consist of regular arguments, unlike the Ksh/Bash ''<​nowiki>​[[</​nowiki>''​ command. While the issue is analogous to ''​let''​ vs ''<​nowiki>​((</​nowiki>'',​ the advantages of ''<​nowiki>​[[</​nowiki>''​ vs ''​[''​ are even more important because the arguments/​expansions aren't just concatenated into one expression. With the classic ''​[''​ command, the number of arguments is significant. If at all possible, use the [[syntax:​ccmd:​conditional_expression | conditional expression]] ("new test command"​) ''<​nowiki>​[[ EXPRESSION ]]</​nowiki>''​. Unless there is a need for POSIX compatibility,​ there are only a few reasons to use ''​[''​. ''<​nowiki>​[[</​nowiki>''​ is one of the most portable and consistent non-POSIX ksh extensions available. See: [[syntax:​ccmd:​conditional_expression]] and //​[[http://​mywiki.wooledge.org/​BashFAQ/​031 | What is the difference between test, [ and [[ ?]]// | |''​[\ EXPRESSION\ ]''​\ and\ ''​test\ EXPRESSION'' ​ |''<​nowiki>​[[</​nowiki>​\ EXPRESSION\ <​nowiki>​]]</​nowiki>'' ​ |''​test''​ and ''​[''​ are the Bourne/​POSIX commands for evaluating test expressions (they are almost identical, and ''​[''​ is somewhat more common). The expressions consist of regular arguments, unlike the Ksh/Bash ''<​nowiki>​[[</​nowiki>''​ command. While the issue is analogous to ''​let''​ vs ''<​nowiki>​((</​nowiki>'',​ the advantages of ''<​nowiki>​[[</​nowiki>''​ vs ''​[''​ are even more important because the arguments/​expansions aren't just concatenated into one expression. With the classic ''​[''​ command, the number of arguments is significant. If at all possible, use the [[syntax:​ccmd:​conditional_expression | conditional expression]] ("new test command"​) ''<​nowiki>​[[ EXPRESSION ]]</​nowiki>''​. Unless there is a need for POSIX compatibility,​ there are only a few reasons to use ''​[''​. ''<​nowiki>​[[</​nowiki>''​ is one of the most portable and consistent non-POSIX ksh extensions available. See: [[syntax:​ccmd:​conditional_expression]] and //​[[http://​mywiki.wooledge.org/​BashFAQ/​031 | What is the difference between test, [ and [[ ?]]// |
-|''​set -e'',​ ''​set -o errexit''​and the ''​ERR''​ trap  |proper control flow and error handling ​ |''​set -e''​ causes untested non-zero exit statuses to be fatal. It is a debugging feature intended for use only during development and should not be used in production code, especially init scripts and other high-availability scripts. Do not be tempted to think of this as "error handling";​ it's not, it's just a way to find the place you'​ve ​''​forgotten'' ​to put error handling. Think of it as akin to "use strict" ​in Perl or "throws" ​in C++: tough love that makes you write better code. Many guides recommend avoiding it entirely because of the apparently-complex rules for when non-zero statuses cause the script to abort. Conversely, large software projects with experienced coders may recommend or even mandate its use. Because it provides no notification of the location of the error, it's more useful combined with ''​set -x''​ or the ''​DEBUG''​ trap and other Bash debug features, and both flags are normally better set on the command line rather than within the script itself. Most of this also applies to the ''​ERR''​ trap, though I've seen it used in a few places in shells that lack ''​pipefail''​ or ''​PIPESTATUS''​. The ''​ERR''​ trap is not POSIX, but ''​set -e''​ is. ''​failglob''​ is another Bash feature that falls into this category (mainly useful for debugging). **The ''​set -e''​ feature generates more questions and false bug reports on the Bash mailing list than all other features combined!** Please do not rely on ''​set -e''​ for logic in scripts. If you still refuse to take this advice, make sure you understand **exactly** how it works. See: //​[[http://​mywiki.wooledge.org/​BashFAQ/​105 | Why doesn'​t set -e (or set -o errexit, or trap ERR) do what I expected?​]]//​ and [[http://​www.fvue.nl/​wiki/​Bash:​_Error_handling]] |+|''​set -e'',​ ''​set -o errexit''​\\ and the ''​ERR''​ trap  |proper control flow and error handling ​ |''​set -e''​ causes untested non-zero exit statuses to be fatal. It is a debugging feature intended for use only during development and should not be used in production code, especially init scripts and other high-availability scripts. Do not be tempted to think of this as "error handling";​ it's not, it's just a way to find the place you'​ve ​//forgotten// to put error handling.\\ Think of it as akin to ''​use strict'' ​in Perl or ''​throws'' ​in C++: tough love that makes you write better code. Many guides recommend avoiding it entirely because of the apparently-complex rules for when non-zero statuses cause the script to abort. Conversely, large software projects with experienced coders may recommend or even mandate its use.\\ Because it provides no notification of the location of the error, it's more useful combined with ''​set -x''​ or the ''​DEBUG''​ trap and other Bash debug features, and both flags are normally better set on the command line rather than within the script itself.\\ Most of this also applies to the ''​ERR''​ trap, though I've seen it used in a few places in shells that lack ''​pipefail''​ or ''​PIPESTATUS''​. The ''​ERR''​ trap is not POSIX, but ''​set -e''​ is. ''​failglob''​ is another Bash feature that falls into this category (mainly useful for debugging).\\ **The ''​set -e''​ feature generates more questions and false bug reports on the Bash mailing list than all other features combined!** Please do not rely on ''​set -e''​ for logic in scripts. If you still refuse to take this advice, make sure you understand **exactly** how it works. See: //​[[http://​mywiki.wooledge.org/​BashFAQ/​105 | Why doesn'​t set -e (or set -o errexit, or trap ERR) do what I expected?​]]//​ and [[http://​www.fvue.nl/​wiki/​Bash:​_Error_handling]] |
 |''​set -u''​ or ''​set -o nounset'' ​ |Proper control flow and error handling ​ |''​set -u''​ causes attempts to expand unset variables or parameters as fatal errors. Like ''​set -e'',​ it bypasses control flow and exits immediately from the current shell environment. Like non-zero statuses, unset variables are a normal part of most non-trivial shell scripts. Living with ''​set -u''​ requires hacks like ''​${1+"​$1"​}''​ for each expansion that might possibly be unset. Only very current shells guarantee that expanding ''​@''​ or ''​*''​ won't trigger an error when no parameters are set ([[http://​austingroupbugs.net/​view.php?​id=155]],​ [[http://​www.in-ulm.de/​~mascheck/​various/​bourne_args/​]]). Apparently some find it useful for debugging. See //​[[http://​mywiki.wooledge.org/​BashFAQ/​083 | How do I determine whether a variable is already defined? Or a function?​]]//​ for how to properly test for defined variables. Don't use ''​set -u''​. | |''​set -u''​ or ''​set -o nounset'' ​ |Proper control flow and error handling ​ |''​set -u''​ causes attempts to expand unset variables or parameters as fatal errors. Like ''​set -e'',​ it bypasses control flow and exits immediately from the current shell environment. Like non-zero statuses, unset variables are a normal part of most non-trivial shell scripts. Living with ''​set -u''​ requires hacks like ''​${1+"​$1"​}''​ for each expansion that might possibly be unset. Only very current shells guarantee that expanding ''​@''​ or ''​*''​ won't trigger an error when no parameters are set ([[http://​austingroupbugs.net/​view.php?​id=155]],​ [[http://​www.in-ulm.de/​~mascheck/​various/​bourne_args/​]]). Apparently some find it useful for debugging. See //​[[http://​mywiki.wooledge.org/​BashFAQ/​083 | How do I determine whether a variable is already defined? Or a function?​]]//​ for how to properly test for defined variables. Don't use ''​set -u''​. |
 |''​${var?​msg}''​ or ''​${var:?​msg}'' ​ |Proper control flow and error handling ​ |Like ''​set -u'',​ this expansion causes a fatal error which immediately exits the current shell environment if the given parameter is unset or is null. It prints the error message given, to the right of the operator. If a value is expected and you'd like to create an assertion or cause errors, it's better to test for undefined variables using one of [[http://​mywiki.wooledge.org/​BashFAQ/​083 | these techniques]] and handle the error manually, or call a ''​die''​ function. This expansion is defined by POSIX. It's better than ''​set -u'',​ because it's explicit, but not by much. It also allows you to accidentally construct hilariously deceptive error messages: <​code>​bash -c 'f() { definitely_not_printf "​${printf:?"​$1"​ - No such option}";​ }; f -v' |''​${var?​msg}''​ or ''​${var:?​msg}'' ​ |Proper control flow and error handling ​ |Like ''​set -u'',​ this expansion causes a fatal error which immediately exits the current shell environment if the given parameter is unset or is null. It prints the error message given, to the right of the operator. If a value is expected and you'd like to create an assertion or cause errors, it's better to test for undefined variables using one of [[http://​mywiki.wooledge.org/​BashFAQ/​083 | these techniques]] and handle the error manually, or call a ''​die''​ function. This expansion is defined by POSIX. It's better than ''​set -u'',​ because it's explicit, but not by much. It also allows you to accidentally construct hilariously deceptive error messages: <​code>​bash -c 'f() { definitely_not_printf "​${printf:?"​$1"​ - No such option}";​ }; f -v'
Line 33: Line 33:
 |''​typeset'' ​ |''​declare'',​ ''​local'',​ ''​export'',​ ''​readonly'' ​ |This is closely related to the above, and should often be used together. ''​typeset''​ exists primarily for ''​ksh''​ compatibility,​ but is marked as "​deprecated"​ in Bash (though I don't entirely agree with this). This makes some sense, because future compatibility can't be guaranteed, and any compatibility at all, requires understanding the non-POSIX features of other shells and their differences. Using ''​declare''​ instead of ''​typeset''​ emphasizes your intention to be "​Bash-only",​ and definitely breaks everywhere else (except possibly zsh if you're lucky). The issue is further complicated by Dash and the [[http://​www.debian.org/​doc/​debian-policy/​ch-files.html#​s-scripts | Debian policy]] requirement for a ''​local''​ builtin, which is itself not entirely compatible with Bash and other shells. | |''​typeset'' ​ |''​declare'',​ ''​local'',​ ''​export'',​ ''​readonly'' ​ |This is closely related to the above, and should often be used together. ''​typeset''​ exists primarily for ''​ksh''​ compatibility,​ but is marked as "​deprecated"​ in Bash (though I don't entirely agree with this). This makes some sense, because future compatibility can't be guaranteed, and any compatibility at all, requires understanding the non-POSIX features of other shells and their differences. Using ''​declare''​ instead of ''​typeset''​ emphasizes your intention to be "​Bash-only",​ and definitely breaks everywhere else (except possibly zsh if you're lucky). The issue is further complicated by Dash and the [[http://​www.debian.org/​doc/​debian-policy/​ch-files.html#​s-scripts | Debian policy]] requirement for a ''​local''​ builtin, which is itself not entirely compatible with Bash and other shells. |
 |''​let '​EXPR'​ '' ​ |''<​nowiki>​((EXPR))</​nowiki>''​ or ''​[\ <​nowiki>​$((EXPR))</​nowiki>​\ -ne\ 0 ]'' ​ |''​let''​ is the "​simple command"​ variant of arithmetic evaluation command, which takes regular arguments. Both ''​let''​ and ''<​nowiki>​((expr))</​nowiki>''​ were present in ksh88, and everything that supports one should support the other. Neither are POSIX. The compound variant is preferable because it doesn'​t take regular arguments for [[syntax:​expansion:​wordsplit | wordsplitting]] and [[syntax:​expansion:​globs | globbing]], which makes it safer and clearer. It is also usually faster, especially in Bash, where compound commands are typically significantly faster. Some of the (few) reasons for using ''​let''​ are detailed on the [[commands:​builtin:​let | let]] page. See [[syntax:​ccmd:​arithmetic_eval | arithmetic evaluation compound command]] | |''​let '​EXPR'​ '' ​ |''<​nowiki>​((EXPR))</​nowiki>''​ or ''​[\ <​nowiki>​$((EXPR))</​nowiki>​\ -ne\ 0 ]'' ​ |''​let''​ is the "​simple command"​ variant of arithmetic evaluation command, which takes regular arguments. Both ''​let''​ and ''<​nowiki>​((expr))</​nowiki>''​ were present in ksh88, and everything that supports one should support the other. Neither are POSIX. The compound variant is preferable because it doesn'​t take regular arguments for [[syntax:​expansion:​wordsplit | wordsplitting]] and [[syntax:​expansion:​globs | globbing]], which makes it safer and clearer. It is also usually faster, especially in Bash, where compound commands are typically significantly faster. Some of the (few) reasons for using ''​let''​ are detailed on the [[commands:​builtin:​let | let]] page. See [[syntax:​ccmd:​arithmetic_eval | arithmetic evaluation compound command]] |
-|''​eval'' ​ |Depends. Often code can be restructured to use better alternatives. ​ |''​eval''​ is thrown in here for good measure, as sadly it is so often misused that any use of ''​eval''​ (even the rare clever one) is immediately dismissed as wrong by experts, and among the most immediate solutions abused by beginners. In reality, there are correct ways to use ''​eval'',​ and even cases in which it's necessary, even in sophisticated shells like Bash and Ksh. ''​eval''​ is unusual in that it is less frequently appropriate in more feature-rich shells than in more minimal shells like Dash, where it is used to compensate for more limitations. If you find yourself needing ''​eval''​ too frequently, it might be a sign that you're either better off using a different language entirely, or trying to borrow an idiom from some other paradigm that isn't well suited to the shell language. By the same token, there are some cases in which working too hard to avoid ''​eval''​ ends up adding a lot of complexity and sacrificing all portability. ​Basically, don't substitute a clever ''​eval''​ for something ​else that's a bit "too clever",​ just to avoid the ''​eval'', ​while still taking ​reasonable measures to avoid it where it is sensible to do so. See: [[commands:​builtin:​eval]] and [[http://​mywiki.wooledge.org/​BashFAQ/​048 | Eval command and security issues]]. |+|''​eval'' ​ |Depends. Often code can be restructured to use better alternatives. ​ |''​eval''​ is thrown in here for good measure, as sadly it is so often misused that any use of ''​eval''​ (even the rare clever one) is immediately dismissed as wrong by experts, and among the most immediate solutions abused by beginners. In reality, there are correct ways to use ''​eval'',​ and even cases in which it's necessary, even in sophisticated shells like Bash and Ksh. ''​eval''​ is unusual in that it is less frequently appropriate in more feature-rich shells than in more minimal shells like Dash, where it is used to compensate for more limitations. If you find yourself needing ''​eval''​ too frequently, it might be a sign that you're either better off using a different language entirely, or trying to borrow an idiom from some other paradigm that isn't well suited to the shell language. By the same token, there are some cases in which working too hard to avoid ''​eval''​ ends up adding a lot of complexity and sacrificing all portability. ​Don't substitute a clever ''​eval''​ for something that's a bit "too clever",​ just to avoid the ''​eval'', ​yet, take reasonable measures to avoid it where it is sensible to do so. See: [[commands:​builtin:​eval]] and [[http://​mywiki.wooledge.org/​BashFAQ/​048 | Eval command and security issues]]. |
  
 ===== See also ===== ===== See also =====
  • scripting/obsolete.txt
  • Last modified: 2019/08/30 16:01
  • by ersen