this post was submitted on 15 Jan 2025
639 points (98.2% liked)

linuxmemes

23847 readers
495 users here now

Hint: :q!


Sister communities:


Community rules (click to expand)

1. Follow the site-wide rules

2. Be civil
  • Understand the difference between a joke and an insult.
  • Do not harrass or attack users for any reason. This includes using blanket terms, like "every user of thing".
  • Don't get baited into back-and-forth insults. We are not animals.
  • Leave remarks of "peasantry" to the PCMR community. If you dislike an OS/service/application, attack the thing you dislike, not the individuals who use it. Some people may not have a choice.
  • Bigotry will not be tolerated.
  • 3. Post Linux-related content
  • Including Unix and BSD.
  • Non-Linux content is acceptable as long as it makes a reference to Linux. For example, the poorly made mockery of sudo in Windows.
  • No porn. Even if you watch it on a Linux machine.
  • 4. No recent reposts
  • Everybody uses Arch btw, can't quit Vim, <loves/tolerates/hates> systemd, and wants to interject for a moment. You can stop now.
  • 5. πŸ‡¬πŸ‡§ Language/язык/Sprache
  • This is primarily an English-speaking community. πŸ‡¬πŸ‡§πŸ‡¦πŸ‡ΊπŸ‡ΊπŸ‡Έ
  • Comments written in other languages are allowed.
  • The substance of a post should be comprehensible for people who only speak English.
  • Titles and post bodies written in other languages will be allowed, but only as long as the above rule is observed.
  • 6. (NEW!) Regarding public figuresWe all have our opinions, and certain public figures can be divisive. Keep in mind that this is a community for memes and light-hearted fun, not for airing grievances or leveling accusations.
  • Keep discussions polite and free of disparagement.
  • We are never in possession of all of the facts. Defamatory comments will not be tolerated.
  • Discussions that get too heated will be locked and offending comments removed.
  • Β 

    Please report posts and comments that break these rules!


    Important: never execute code or follow advice that you don't understand or can't verify, especially here. The word of the day is credibility. This is a meme community -- even the most helpful comments might just be shitposts that can damage your system. Be aware, be smart, don't remove France.

    founded 2 years ago
    MODERATORS
     

    Explanation for newbies:

    • Shell is the programming language that you use when you open a terminal on linux or mac os. Well, actually "shell" is a family of languages with many different implementations (bash, dash, ash, zsh, ksh, fish, ....)

    • Writing programs in shell (called "shell scripts") is a harrowing experience because the language is optimized for interactive use at a terminal, not writing extensive applications

    • The two lines in the meme change the shell's behavior to be slightly less headache-inducing for the programmer:

      • set -euo pipefail is the short form of the following three commands:
        • set -e: exit on the first command that fails, rather than plowing through ignoring all errors
        • set -u: treat references to undefined variables as errors
        • set -o pipefail: If a command piped into another command fails, treat that as an error
      • export LC_ALL=C tells other programs to not do weird things depending on locale. For example, it forces seq to output numbers with a period as the decimal separator, even on systems where coma is the default decimal separator (russian, dutch, etc.).
    • The title text references "posix", which is a document that standardizes, among other things, what features a shell must have. Posix does not require a shell to implement pipefail, so if you want your script to run on as many different platforms as possible, then you cannot use that feature.

    top 50 comments
    sorted by: hot top controversial new old
    [–] [email protected] 31 points 2 months ago (1 children)

    Does this joke have a documentation page?

    [–] [email protected] 23 points 2 months ago

    unironically, yes

    [–] [email protected] 5 points 2 months ago

    I'm fine with my shell scripts not running on a PDP11.

    [–] [email protected] 5 points 2 months ago* (last edited 2 months ago) (1 children)

    My only issue is -u. How do you print help text if your required parameters are always filled. There's no way to test for -z if the shell bails on the first line.

    Edit: though I guess you could initialise your vars with bad defaults, and test for those.

    [–] [email protected] 12 points 2 months ago (2 children)
    #!/bin/bash
    set -euo pipefail
    
    if [[ -z "${1:-}" ]]
    then
      echo "we need an argument!" >&2
      exit 1
    fi
    
    [–] [email protected] 5 points 2 months ago (1 children)

    God I love bash. There's always something to learn.

    my logical steps

    • #! yup
    • if sure!
    • [[ -z makes sense
    • ${1:-} WHAT IN SATANS UNDERPANTS.... parameter expansion I think... reads docs ... default value! shit that's nice.

    it's like buying a really simple generic car then getting excited because it actually has a spare and cupholders.

    [–] [email protected] 3 points 2 months ago

    Yeah, there's also a subtle difference between ${1:-} and ${1-}: The first substitutes if 1 is unset or ""; the second only if 1 is unset. So possibly ${foo-} is actually the better to use for a lot of stuff, if the empty string is a valid value. There's a lot to bash parameter expansion, and it's all punctuation, which ups the line noise-iness of your scripts.

    I don't find it particularly legible or memorable; plus I'm generally not a fan of the variable amount of numbered arguments rather than being able to specify argument numbers and names like we are in practically every other programming language still in common use.

    [–] [email protected] 3 points 2 months ago* (last edited 2 months ago) (1 children)

    That's good, but if you like to name your arguments first before testing them, then it falls apart

    #!/bin/bash
    set -euo pipefail
    
    myarg=$1
    
    if [[ -z "${myarg}" ]]
    then
      echo "we need an argument!" >&2
      exit 1
    fi
    

    This fails. The solution is to do myarg=${1:-} and then test

    Edit: Oh, I just saw you did that initialisation in the if statement. Take your trophy and leave.

    [–] [email protected] 2 points 2 months ago* (last edited 2 months ago) (1 children)

    Yeah, another way to do it is

    #!/bin/bash
    set -euo pipefail
    
    if [[ $# -lt 1 ]]
    then
      echo "Usage: $0 argument1" >&2
      exit 1
    fi
    

    i.e. just count arguments. Related, fish has kind of the orthogonal situation here, where you can name arguments in a better way, but there's no set -u

    function foo --argument-names bar
      ...
    end
    

    in the end my conclusion is that argument handling in shells is generally bad. Add in historic workarounds like if [ "x" = "x$1" ] and it's clear shells have always been Shortcut City


    Side note: One point I have to award to Perl for using eq/lt/gt/etc for string comparisons and ==/</> for numeric comparisons. In shells it's reversed for some reason? The absolute state of things when I can point to Perl as an example of something that did it better

    [–] [email protected] 2 points 2 months ago (1 children)

    Perl is the original GOAT! It took a look at shell, realised it could do (slightly) better, and forged its own hacky path!

    [–] [email protected] 2 points 2 months ago* (last edited 2 months ago)

    I was about to say, half the things people write complex shell scripts for, I'll just do in something like Perl, Ruby, Python, even node/TS, because they have actual type systems and readability. And library support. Always situation-dependent though.

    [–] [email protected] 4 points 2 months ago (1 children)

    I was never a fan of set -e. I prefer to do my own error handling. But, I never understood why pipefail wasn't the default. A failure is a failure. I would like to know about it!

    [–] [email protected] 3 points 2 months ago (1 children)

    IIRC if you pipe something do head it will stop reading after some lines and close the pipe, leading to a pipe fail even if everything works correctly

    [–] [email protected] 3 points 2 months ago

    Yeah, I had a silly hack for that. I don't remember what it was. It's been 3-4 years since I wrote bash for a living. While not perfect, I still need to know if a pipeline command failed. Continuing a script after an invisible error, in many cases, could have been catastrophic.

    [–] [email protected] 82 points 2 months ago

    This joke comes with more documentation than most packages.

    [–] [email protected] -2 points 2 months ago* (last edited 2 months ago) (2 children)

    just use python instead.

    • wrap around subprocess.run(), to call to system utils
    • use pathlib.Path for file paths and reading/writing to files
    • use shutil.which() to resolve utilities from your Path env var

    Here's an example of some python i use to launch vscode (and terminals, but that requires dbus)

    
    from pathlib import Path
    from shutil import which
    from subprocess import run
    
    def _run(cmds: list[str], cwd=None):
        p = run(cmds, cwd=cwd)
    
        # raises an error if return code is non-zero
        p.check_returncode()
    
        return p
    
    VSCODE = which('code')
    SUDO   = which('sudo')
    DOCKER = which('docker')
    
    proj_dir = Path('/path/to/repo')
    
    docker_compose = proj_dir / 'docker/'
    
    windows = [
      proj_dir / 'code',
      proj_dir / 'more_code',
      proj_dir / 'even_more_code/subfolder',
    ]
    for w in windows:
      _run([VSCODE, w])
    
    _run([SUDO, DOCKER, 'compose', 'up', '-d'], cwd=docker_compose)
    
    [–] [email protected] 1 points 2 months ago

    Or Rust. Use Command::new() for system commands and Path::new() for paths.

    [–] [email protected] 10 points 2 months ago (1 children)

    Cool, now pipe something into something else

    [–] [email protected] 1 points 2 months ago* (last edited 2 months ago)

    that is a little more complicated

    p.communicate() will take a string (or bytes) and send it to the stdin of the process, then wait for p to finish execution

    there are ways to stream input into a running process (without waiting for the process to finish), but I don't remember how off the top of my head

    
    from shutil import which
    from subprocess import Popen, PIPE, run
    from pathlib import Path
    
    LS   = which('ls')
    REV  = which('rev')
    
    ls   = run([LS, Path.home()], stdout=PIPE)
    
    p = Popen([REV], stdin=PIPE, stdout=PIPE)
    stdout, stderr = p.communicate(ls.stdout)
    
    print(stdout.decode('utf-8'))
    
    [–] [email protected] 7 points 2 months ago (1 children)

    Nushell has pipefail by default (plus an actual error system that integrates with status codes) and has actual number values, don't have these problems

    [–] [email protected] 1 points 2 months ago (1 children)

    nushell is pretty good. I use it for my main shell

    although, i still prefer writing utilities in python over nu scripts

    [–] [email protected] 1 points 2 months ago

    Nushell is great as a more powerful scripting language, but a proper language like python is useful too

    [–] [email protected] 9 points 2 months ago (1 children)

    Powershell is the future

    • Windows and office365 admins
    [–] [email protected] 3 points 2 months ago (1 children)

    I even use powershell as my main scripting language on my Mac now. I’ve come around.

    [–] [email protected] 3 points 2 months ago (1 children)

    That's sounds terrible honestly

    [–] [email protected] 1 points 2 months ago

    I’m so used to using powershell to handle collections and pipelines that I find I want it for small scripts on Mac. For instance, I was using ffmpeg to alter a collection of files on my Mac recently. I found it super simple to use Powershell to handle the logic. I could have used other tools, but I didn’t find anything about it terrible.

    load more comments
    view more: next β€Ί