Skip to main content
List item continuation paragraphs
Source Link
Toby Speight
  • 9.4k
  • 3
  • 32
  • 54
  1. Most people use case statements for option processing because it's simple and easy and it works. There are countless examples using either built-in getopts or /usr/bin/getopt or custom/hand-crafted. It often IS the better method, and certainly better/more-readable than a bunch of if/elif/else statements.

  2. POSIX sh does not support regex tests. For that, you need a shell like bash, ksh, or zsh, it's one of the reasons why the [[ ... ]] built-in was invented - to do stuff that [ aka test can't do without breaking compatibility.

    Or you could use awk to do your matching but (like most external programs) it's not something you'd want to fork repeatedly in a shell loop - the advantage of a built-in is that it IS built-in. Or you could use perl, but in that case it would make more sense to just write the entire script in perl.

  3. If you're not going to use nocasematch then at least use tr '[:upper:]' '[:lower:]' or similar to convert $action to all lower-case (or upper, it doesn't matter) before trying to match it against something.

    Then you wouldn't need all those ugly and unreadable and tedious to type & edit bracket expressions just to match mixed-case. That all looks like you're going out of your way to make things harder for yourself when you should be trying to make things easier and simpler. Converting to all lower or all upper case would also benefit matching with a case statement as well as regex.

    BTW, those [upper:] and [:lower:] classes work with at least GNU and BSD tr, maybe others too. As @Stephane mentions, GNU tr doesn't support multi-byte characters, so tr A-Z a-z works too. It's not unreasonable to expect that it, or some other version of tr, will one day work correctly for multi-byte unicode characters. If handling unicode options is important to you, use a unicode-capable tool like perl (which has a built-in lc function for case conversion) to do the case conversion.

  4. You should use a heredoc rather than multiple printf statements for long sequences of text. It's not like you're actually using any of printf's formatting options (and if needed, you can use heredocs with printf). Also, all that embedded whitespace at the end of each line will annoy users, as it will end up in the selection or clipboard if copied. e.g.

    cat <<__EOF__
    Usage: pocsag [ACTION] [INPUTMETHOD/REDACTION] [OUTPUTMETHOD/PATHTOFILE/SERVICEACTION]                         Examples:        
      pocsag decode rtlsdr cli  
      pocsag decode netcat file
      pocsag redact medical ~/media/signals/pocsag/decoded/POCSAG*
      pocsag service rtlsdr start
    
    Actions:
      decode                    Envoke the usage of the input tuner, sox and multimon-ng to decode the signals.
      redact                    Copy file but redact regex matching lines of a file. For example: Removing medical TXs. 
      service                   Used to start/stop the systemd service in user's ~/.config. Relies on rtlsdr_pager_rx
    
    Input Methods:              
      rtlsdr                    Use an RTLSDR device plugged into the local computer.
      netcat                    Listen to localhost:7355 using netcat, then process and output locally.                 
    
    __EOF__
    

    This is more readable, easier to edit, and easier to re-format if/when needed with fmt, fold, par, or similar. It's just text, with no embedded code.

  5. Put your usage message in a function called, e.g. usage. And same for other if or case clauses with multiple lines of code or long strings of text to print. You don't want to embed lots of text or code in a case statement or a long if/else/elif/then/fi statement - something like that should be readable at a glance without needing to page forwards and backwards just to get an overview of what the entire statement is doing.

cat <<__EOF__
Usage: pocsag [ACTION] [INPUTMETHOD/REDACTION] [OUTPUTMETHOD/PATHTOFILE/SERVICEACTION]                         Examples:        
  pocsag decode rtlsdr cli  
  pocsag decode netcat file
  pocsag redact medical ~/media/signals/pocsag/decoded/POCSAG*
  pocsag service rtlsdr start
  
Actions:
  decode                    Envoke the usage of the input tuner, sox and multimon-ng to decode the signals.
  redact                    Copy file but redact regex matching lines of a file. For example: Removing medical TXs. 
  service                   Used to start/stop the systemd service in user's ~/.config. Relies on rtlsdr_pager_rx
     
Input Methods:              
  rtlsdr                    Use an RTLSDR device plugged into the local computer.
  netcat                    Listen to localhost:7355 using netcat, then process and output locally.                 

__EOF__

This is more readable, easier to edit, and easier to re-format if/when needed with fmt, fold, par, or similar. It's just text, with no embedded code.

  1. Put your usage message in a function called, e.g. usage. And same for other if or case clauses with multiple lines of code or long strings of text to print. You don't want to embed lots of text or code in a case statement or a long if/else/elif/then/fi statement - something like that should be readable at a glance without needing to page forwards and backwards just to get an overview of what the entire statement is doing.
  1. Most people use case statements for option processing because it's simple and easy and it works. There are countless examples using either built-in getopts or /usr/bin/getopt or custom/hand-crafted. It often IS the better method, and certainly better/more-readable than a bunch of if/elif/else statements.

  2. POSIX sh does not support regex tests. For that, you need a shell like bash, ksh, or zsh, it's one of the reasons why the [[ ... ]] built-in was invented - to do stuff that [ aka test can't do without breaking compatibility.

    Or you could use awk to do your matching but (like most external programs) it's not something you'd want to fork repeatedly in a shell loop - the advantage of a built-in is that it IS built-in. Or you could use perl, but in that case it would make more sense to just write the entire script in perl.

  3. If you're not going to use nocasematch then at least use tr '[:upper:]' '[:lower:]' or similar to convert $action to all lower-case (or upper, it doesn't matter) before trying to match it against something.

    Then you wouldn't need all those ugly and unreadable and tedious to type & edit bracket expressions just to match mixed-case. That all looks like you're going out of your way to make things harder for yourself when you should be trying to make things easier and simpler. Converting to all lower or all upper case would also benefit matching with a case statement as well as regex.

    BTW, those [upper:] and [:lower:] classes work with at least GNU and BSD tr, maybe others too. As @Stephane mentions, GNU tr doesn't support multi-byte characters, so tr A-Z a-z works too. It's not unreasonable to expect that it, or some other version of tr, will one day work correctly for multi-byte unicode characters. If handling unicode options is important to you, use a unicode-capable tool like perl (which has a built-in lc function for case conversion) to do the case conversion.

  4. You should use a heredoc rather than multiple printf statements for long sequences of text. It's not like you're actually using any of printf's formatting options (and if needed, you can use heredocs with printf). Also, all that embedded whitespace at the end of each line will annoy users, as it will end up in the selection or clipboard if copied. e.g.

cat <<__EOF__
Usage: pocsag [ACTION] [INPUTMETHOD/REDACTION] [OUTPUTMETHOD/PATHTOFILE/SERVICEACTION]                         Examples:        
  pocsag decode rtlsdr cli  
  pocsag decode netcat file
  pocsag redact medical ~/media/signals/pocsag/decoded/POCSAG*
  pocsag service rtlsdr start
  
Actions:
  decode                    Envoke the usage of the input tuner, sox and multimon-ng to decode the signals.
  redact                    Copy file but redact regex matching lines of a file. For example: Removing medical TXs. 
  service                   Used to start/stop the systemd service in user's ~/.config. Relies on rtlsdr_pager_rx
     
Input Methods:              
  rtlsdr                    Use an RTLSDR device plugged into the local computer.
  netcat                    Listen to localhost:7355 using netcat, then process and output locally.                 

__EOF__

This is more readable, easier to edit, and easier to re-format if/when needed with fmt, fold, par, or similar. It's just text, with no embedded code.

  1. Put your usage message in a function called, e.g. usage. And same for other if or case clauses with multiple lines of code or long strings of text to print. You don't want to embed lots of text or code in a case statement or a long if/else/elif/then/fi statement - something like that should be readable at a glance without needing to page forwards and backwards just to get an overview of what the entire statement is doing.
  1. Most people use case statements for option processing because it's simple and easy and it works. There are countless examples using either built-in getopts or /usr/bin/getopt or custom/hand-crafted. It often IS the better method, and certainly better/more-readable than a bunch of if/elif/else statements.

  2. POSIX sh does not support regex tests. For that, you need a shell like bash, ksh, or zsh, it's one of the reasons why the [[ ... ]] built-in was invented - to do stuff that [ aka test can't do without breaking compatibility.

    Or you could use awk to do your matching but (like most external programs) it's not something you'd want to fork repeatedly in a shell loop - the advantage of a built-in is that it IS built-in. Or you could use perl, but in that case it would make more sense to just write the entire script in perl.

  3. If you're not going to use nocasematch then at least use tr '[:upper:]' '[:lower:]' or similar to convert $action to all lower-case (or upper, it doesn't matter) before trying to match it against something.

    Then you wouldn't need all those ugly and unreadable and tedious to type & edit bracket expressions just to match mixed-case. That all looks like you're going out of your way to make things harder for yourself when you should be trying to make things easier and simpler. Converting to all lower or all upper case would also benefit matching with a case statement as well as regex.

    BTW, those [upper:] and [:lower:] classes work with at least GNU and BSD tr, maybe others too. As @Stephane mentions, GNU tr doesn't support multi-byte characters, so tr A-Z a-z works too. It's not unreasonable to expect that it, or some other version of tr, will one day work correctly for multi-byte unicode characters. If handling unicode options is important to you, use a unicode-capable tool like perl (which has a built-in lc function for case conversion) to do the case conversion.

  4. You should use a heredoc rather than multiple printf statements for long sequences of text. It's not like you're actually using any of printf's formatting options (and if needed, you can use heredocs with printf). Also, all that embedded whitespace at the end of each line will annoy users, as it will end up in the selection or clipboard if copied. e.g.

    cat <<__EOF__
    Usage: pocsag [ACTION] [INPUTMETHOD/REDACTION] [OUTPUTMETHOD/PATHTOFILE/SERVICEACTION]                         Examples:        
      pocsag decode rtlsdr cli  
      pocsag decode netcat file
      pocsag redact medical ~/media/signals/pocsag/decoded/POCSAG*
      pocsag service rtlsdr start
    
    Actions:
      decode                    Envoke the usage of the input tuner, sox and multimon-ng to decode the signals.
      redact                    Copy file but redact regex matching lines of a file. For example: Removing medical TXs. 
      service                   Used to start/stop the systemd service in user's ~/.config. Relies on rtlsdr_pager_rx
    
    Input Methods:              
      rtlsdr                    Use an RTLSDR device plugged into the local computer.
      netcat                    Listen to localhost:7355 using netcat, then process and output locally.                 
    
    __EOF__
    

    This is more readable, easier to edit, and easier to re-format if/when needed with fmt, fold, par, or similar. It's just text, with no embedded code.

  5. Put your usage message in a function called, e.g. usage. And same for other if or case clauses with multiple lines of code or long strings of text to print. You don't want to embed lots of text or code in a case statement or a long if/else/elif/then/fi statement - something like that should be readable at a glance without needing to page forwards and backwards just to get an overview of what the entire statement is doing.

added 823 characters in body
Source Link
cas
  • 84.9k
  • 9
  • 138
  • 207
  1. Most people use case statements for option processing because it's simple and easy and it works. There are countless examples using either built-in getopts or /usr/bin/getopt or custom/hand-crafted. IfIt often IS the better method, and certainly better/more-readable than a bunch of if/elif/else statements.

  2. POSIX sh does not support regex tests. For that, you need a shell like bash, ksh, or zsh, it's one of the reasons why the [[ ... ]] built-in was invented - to do stuff that [ aka test can't do without breaking backwards compatibility.

    Or you could use awk to do your matching but (like most external programs) it's not something you'd want to fork repeatedly in a shell loop - the advantage of a built-in is that it IS built-in. Or you could use perl, but in that case it would make more sense to just write the entire script in perl.

  3. If you're not going to use nocasematch then at least use tr '[:upper:]' '[:lower:]' or similar to convert $action to all lower-case (or upper, it doesn't matter) before trying to match it against something.

    Then you wouldn't need all those ugly and unreadable and tedious to type & edit bracket expressions just to match mixed-case. That all looks like you're going out of your way to make things harder for yourself when you should be trying to make things easier and simpler. Converting to all lower or all upper case would also benefit matching with a case statement as well as regex.

    BTW, those [upper:] and [:lower:] classes work with at least GNU and BSD tr, maybe others too. As @Stephane mentions, GNU tr doesn't support multi-byte characters, so tr A-Z a-z works too. It's not unreasonable to expect that it, or some other version of tr, will one day work correctly for multi-byte unicode characters. If handling unicode options is important to you, use a unicode-capable tool like perl (which has a built-in lc function for case conversion) to do the case conversion.

  4. You should use a heredoc rather than multiple printf statements for long sequences of text. It's not like you're actually using any of printf's formatting options (and if needed, you can use heredocs with printf). Also, all that embedded whitespace at the end of each line will annoy users, as it will end up in the selection or clipboard if copied. e.g.


PS: I mention readability a lot here - that's because for any code where performance isn't critical (e.g. shell scripts - any performance-critical parts of the task should be done by external programs, not by shell itself) it's always better to choose readability over "clever tricks" or performance, especially if the trick or "optimisation" adds nothing of any real, practical value.

Code needs to be maintained and readable code is easier to maintain, and easier to understand when you need to update it in six months (or six years). As a general rule, an unreadable mess will require at least as much time and effort to understand by future you or somebody else as it took to write in the first place....probably a lot more, because it's much easier to write something new than to decipher obfuscated cruft.

  1. Most people use case statements for option processing because it's simple and easy and it works. There are countless examples using either built-in getopts or /usr/bin/getopt or custom/hand-crafted. If often IS the better method, and certainly better/more-readable than a bunch of if/elif/else statements.

  2. POSIX sh does not support regex tests. For that, you need a shell like bash, ksh, zsh, it's one of the reasons why the [[ ... ]] built-in was invented - to do stuff that [ aka test can't do without breaking backwards compatibility.

    Or you could use awk to do your matching but (like most external programs) it's not something you'd want to fork repeatedly in a shell loop - the advantage of a built-in is that it IS built-in. Or you could use perl, but in that case it would make more sense to just write the entire script in perl.

  3. If you're not going to use nocasematch then at least use tr '[:upper:]' '[:lower:]' or similar to convert $action to all lower-case (or upper, it doesn't matter) before trying to match it against something.

    Then you wouldn't need all those ugly and unreadable and tedious to type & edit bracket expressions just to match mixed-case. That all looks like you're going out of your way to make things harder for yourself when you should be trying to make things easier and simpler. Converting to all lower or all upper case would also benefit matching with a case statement as well as regex.

    BTW, those [upper:] and [:lower:] classes work with at least GNU and BSD tr, maybe others too. As @Stephane mentions, GNU tr doesn't support multi-byte characters, so tr A-Z a-z works too. It's not unreasonable to expect that it, or some other version of tr, will one day work correctly for multi-byte unicode characters. If handling unicode options is important to you, use a unicode-capable tool like perl (which has a built-in lc function for case conversion) to do the case conversion.

  4. You should use a heredoc rather than multiple printf statements for long sequences of text. It's not like you're actually using any of printf's formatting options (and if needed, you can use heredocs with printf). Also, all that embedded whitespace at the end of each line will annoy users, as it will end up in the selection or clipboard if copied. e.g.

  1. Most people use case statements for option processing because it's simple and easy and it works. There are countless examples using either built-in getopts or /usr/bin/getopt or custom/hand-crafted. It often IS the better method, and certainly better/more-readable than a bunch of if/elif/else statements.

  2. POSIX sh does not support regex tests. For that, you need a shell like bash, ksh, or zsh, it's one of the reasons why the [[ ... ]] built-in was invented - to do stuff that [ aka test can't do without breaking compatibility.

    Or you could use awk to do your matching but (like most external programs) it's not something you'd want to fork repeatedly in a shell loop - the advantage of a built-in is that it IS built-in. Or you could use perl, but in that case it would make more sense to just write the entire script in perl.

  3. If you're not going to use nocasematch then at least use tr '[:upper:]' '[:lower:]' or similar to convert $action to all lower-case (or upper, it doesn't matter) before trying to match it against something.

    Then you wouldn't need all those ugly and unreadable and tedious to type & edit bracket expressions just to match mixed-case. That all looks like you're going out of your way to make things harder for yourself when you should be trying to make things easier and simpler. Converting to all lower or all upper case would also benefit matching with a case statement as well as regex.

    BTW, those [upper:] and [:lower:] classes work with at least GNU and BSD tr, maybe others too. As @Stephane mentions, GNU tr doesn't support multi-byte characters, so tr A-Z a-z works too. It's not unreasonable to expect that it, or some other version of tr, will one day work correctly for multi-byte unicode characters. If handling unicode options is important to you, use a unicode-capable tool like perl (which has a built-in lc function for case conversion) to do the case conversion.

  4. You should use a heredoc rather than multiple printf statements for long sequences of text. It's not like you're actually using any of printf's formatting options (and if needed, you can use heredocs with printf). Also, all that embedded whitespace at the end of each line will annoy users, as it will end up in the selection or clipboard if copied. e.g.


PS: I mention readability a lot here - that's because for any code where performance isn't critical (e.g. shell scripts - any performance-critical parts of the task should be done by external programs, not by shell itself) it's always better to choose readability over "clever tricks" or performance, especially if the trick or "optimisation" adds nothing of any real, practical value.

Code needs to be maintained and readable code is easier to maintain, and easier to understand when you need to update it in six months (or six years). As a general rule, an unreadable mess will require at least as much time and effort to understand by future you or somebody else as it took to write in the first place....probably a lot more, because it's much easier to write something new than to decipher obfuscated cruft.

added 405 characters in body
Source Link
cas
  • 84.9k
  • 9
  • 138
  • 207
  1. Most people use case statements for option processing because it's simple and easy and it works. There are countless examples using either built-in getopts or /usr/bin/getopt or custom/hand-crafted. If often IS the better method, and certainly better/more-readable than a bunch of if/else/elif/thenelse statements.

  2. POSIX sh does not support regex tests. For that, you need a shell like bash, ksh, zsh, it's one of the reasons why the [[ ... ]] built-in was invented - to do stuff that [ aka test can't do without breaking backwards compatibility.

    Or you could use awk to do your matching but (like most external programs) it's not something you'd want to fork repeatedly in a shell loop - the advantage of a built-in is that it IS built-in. Or you could use perl, but in that case it would make more sense to just write the entire script in perl.

  3. If you're not going to use nocasematch then at least use tr '[:upper:]' '[:lower:]' or similar to convert $action to all lower-case (or upper, it doesn't matter) before trying to match it against something.

    Then you wouldn't need all those ugly and unreadable and tedious to type & edit bracket expressions just to match mixed-case. That all looks like you're going out of your way to make things harder for yourself when you should be trying to make things easier and simpler. Converting to all lower or all upper case would also benefit matching with a case statement as well as regex.

    BTW, those [upper:] and [:lower:] classes work with at least GNU and BSD tr, maybe others too.   As @Stephane mentions, GNU tr doesn't support multi-byte characters, so tr A-Z a-z works too. It's not unreasonable to expect that it, or some other version of tr, will one day work correctly for ASCIImulti-byte unicode characters. If handling unicode options is important to you, use a unicode-capable tool like perl (which has a built-in lc function for case conversion) to do the case conversion.

  4. You should use a heredoc rather than multiple printf statements for long sequences of text. It's not like you're actually using any of printf's formatting options (and if needed, you can use heredocs with printf). Also, all that embedded whitespace at the end of each line will annoy users, as it will end up in the selection or clipboard if copied. e.g.

  1. Put your usage message in a function called, e.g. usage. And same for other if or case clauses with multiple lines of code or long strings of text to print. You don't want to embed lots of text or code in a case statement or a long if/else/elif/then/fi statement - something like that should be readable at a glance without needing to page forwards and backwards just to get an overview of what the entire statement is doing.
  1. Most people use case statements for option processing because it's simple and easy and it works. There are countless examples using either built-in getopts or /usr/bin/getopt or custom/hand-crafted. If often IS the better method, and certainly better/more-readable than a bunch of if/else/elif/then statements.

  2. POSIX sh does not support regex tests. For that, you need a shell like bash, ksh, zsh, it's one of the reasons why the [[ ... ]] built-in was invented - to do stuff that [ aka test can't do without breaking backwards compatibility.

    Or you could use awk to do your matching but (like most external programs) it's not something you'd want to fork repeatedly in a shell loop - the advantage of a built-in is that it IS built-in. Or you could use perl, but in that case it would make more sense to just write the entire script in perl.

  3. If you're not going to use nocasematch then at least use tr '[:upper:]' '[:lower:]' or similar to convert $action to all lower-case (or upper, it doesn't matter) before trying to match it against something.

    Then you wouldn't need all those ugly and unreadable and tedious to type & edit bracket expressions just to match mixed-case. That all looks like you're going out of your way to make things harder for yourself when you should be trying to make things easier and simpler. Converting to all lower or all upper case would also benefit matching with a case statement as well as regex.

    BTW, those [upper:] and [:lower:] classes work with at least GNU and BSD tr, maybe others too.  tr A-Z a-z works for ASCII.

  4. You should use a heredoc rather than multiple printf statements for long sequences of text. It's not like you're actually using any of printf's formatting options. Also, all that embedded whitespace at the end of each line will annoy users, as it will end up in the selection or clipboard if copied. e.g.

  1. Put your usage message in a function called, e.g. usage. And same for if or case clauses with multiple lines of code or long strings of text to print. You don't want to embed lots of text or code in a case statement or a long if/else/elif/then/fi statement - something like that should be readable at a glance without needing to page forwards and backwards just to get an overview of what the entire statement is doing.
  1. Most people use case statements for option processing because it's simple and easy and it works. There are countless examples using either built-in getopts or /usr/bin/getopt or custom/hand-crafted. If often IS the better method, and certainly better/more-readable than a bunch of if/elif/else statements.

  2. POSIX sh does not support regex tests. For that, you need a shell like bash, ksh, zsh, it's one of the reasons why the [[ ... ]] built-in was invented - to do stuff that [ aka test can't do without breaking backwards compatibility.

    Or you could use awk to do your matching but (like most external programs) it's not something you'd want to fork repeatedly in a shell loop - the advantage of a built-in is that it IS built-in. Or you could use perl, but in that case it would make more sense to just write the entire script in perl.

  3. If you're not going to use nocasematch then at least use tr '[:upper:]' '[:lower:]' or similar to convert $action to all lower-case (or upper, it doesn't matter) before trying to match it against something.

    Then you wouldn't need all those ugly and unreadable and tedious to type & edit bracket expressions just to match mixed-case. That all looks like you're going out of your way to make things harder for yourself when you should be trying to make things easier and simpler. Converting to all lower or all upper case would also benefit matching with a case statement as well as regex.

    BTW, those [upper:] and [:lower:] classes work with at least GNU and BSD tr, maybe others too. As @Stephane mentions, GNU tr doesn't support multi-byte characters, so tr A-Z a-z works too. It's not unreasonable to expect that it, or some other version of tr, will one day work correctly for multi-byte unicode characters. If handling unicode options is important to you, use a unicode-capable tool like perl (which has a built-in lc function for case conversion) to do the case conversion.

  4. You should use a heredoc rather than multiple printf statements for long sequences of text. It's not like you're actually using any of printf's formatting options (and if needed, you can use heredocs with printf). Also, all that embedded whitespace at the end of each line will annoy users, as it will end up in the selection or clipboard if copied. e.g.

  1. Put your usage message in a function called, e.g. usage. And same for other if or case clauses with multiple lines of code or long strings of text to print. You don't want to embed lots of text or code in a case statement or a long if/else/elif/then/fi statement - something like that should be readable at a glance without needing to page forwards and backwards just to get an overview of what the entire statement is doing.
added 45 characters in body
Source Link
cas
  • 84.9k
  • 9
  • 138
  • 207
Loading
Source Link
cas
  • 84.9k
  • 9
  • 138
  • 207
Loading