Live data from Hacker News

A shell colon does nothing. Use it anyway

refp.se

141–150 of 191 posts

Re: A shell colon does nothing. Use it anyway

#141
post #140

Articles like this are fun but they all come from posix shell syntax being fundamentally bad for scripting/programming. All the piping stuff is great, of course. And the overall ecosystem is great. But the interpretation of the script itself working by a series of string substitutions is a mechanism we wouldn't accept in a regular programming language. And there's no excuse for it really, except that shell syntax is…

> fundamentally bad for scripting/programming […] a mechanism we wouldn’t accept in a regular programming language I don’t agree with this assumption that shell should use mechanisms we accept in “regular” programming languages, whatever that means. And why not the other way around? Why do we accept mechanisms in programming that we wouldn’t accept in a shell? There are layers of assumption in your assumption. I also…

a bunch of happy xonsh users disagree

Re: A shell colon does nothing. Use it anyway

#142
post #34

> ( : The subshell execution parentheses and the colon are superfluous here, just: Redirections do not require a colon command to hang off of, and there is no need to fork a subshell to execute such a command. > ( : >> result.json ) && echo YES # is result.json writable? As a go-to idiom for a writability test, it gives me pause. If the file didn't exist, we created a zero-length one. That might be okay if we are goi…

They are NOT superflous, and all you need to prove it is `zsh` (but there are others that follow suit in similar fashions): zsh% echo "hello world" > data zsh% So, if you want something that "everyone can use" without going into details about the difference between commonly used shells.. you'd use the null-command. --- and given that we use the null-command, it _WILL_ behave different with or without subshell.. and a…

  zsh%  /dev/null && echo READABLE   # 
Maybe zsh still reads the entire file and copies it to /dev/null, which would be a severe performance problem for large files.

The colon by itself, without the subprocess, also prevents the dumping to stdout:

  zsh% : 
However, with the subprocess parentheses, we can redirect the nonexistence diagnostic to /dev/null, which I don't see mentioned or exemplified in the article:

  zsh% :  /dev/null && echo READABLE
  zsh: no such file or directory: nonexistent
  zsh% (:  /dev/null && echo READABLE
The normal way of testing whether something exists and is readable that you would actually use in production script looks more like this:

  $ test -r file && echo YES
  $ [ -r file ] && echo YES
so we are talking about obfuscated coding.

I would say that "if you want something everyone can use", the -r test would be the first candidate.

BTW, why not bring up the strawman of tcsh?

  tcsh% 
Yes, if we want an obfuscated readability test which works literally in any shell that is currently still in deployment in systems that permit new scripts to be installed and run, it looks like do need that colon.

However, fish doesn't like &&:

  fish>  : 
Does it support test -r?

  fish> test -r nonexistent
  fish> test -r nonexistent; and echo yes
  fish> test -r /etc/hosts; and echo yes
  yes
Not parentheses though:

  fish> ( test -r /etc/hosts ); and echo yes
  fish: Illegal command name “( test -r /etc/hosts )”
We clearly have to restrict the idea of what "everyone can use" to POSIX-like shells; there is no getting around shell differences absolutely, other than for perhaps trivial command invocations.

Re: A shell colon does nothing. Use it anyway

#143

Earlier quoted context omitted.

I will immediately remove all the shell scripts on my system based on this comment alone. Posted from my phone since my system came crashing down.

Heh, I like that. We are indeed stuck with posix shell syntax; I didn't claim we weren't.

I don't consider it being stuck at all. And that's coming from a die hard C and assembly language programmer.

Re: A shell colon does nothing. Use it anyway

#144
post #140

Earlier quoted context omitted.

> fundamentally bad for scripting/programming […] a mechanism we wouldn’t accept in a regular programming language I don’t agree with this assumption that shell should use mechanisms we accept in “regular” programming languages, whatever that means. And why not the other way around? Why do we accept mechanisms in programming that we wouldn’t accept in a shell? There are layers of assumption in your assumption. I also…

a bunch of happy xonsh users disagree

Hey good! I’d like a good python shell. Does xonsh fix cut and paste with python? The first huge problem I ran into with python shelling is you can’t cut as paste indented code at all.

Edit I’m reading about it, here are some notes to myself:

Sounds like there are 2 modes, subprocess & python

Env vars are still string substitution, and there are many rules and string literal prefixes.

You will want the prompt toolkit (ptk). It’s an additional install. (Non-default installs, btw, are why I stopped using zsh. I loved zsh, but had to move to bash.)

Regexes use backticks

@.imp for inline imports… good idea

BTW I googled for xonsh complaints and got what I expected; awkward & klunky interactive editing, special prefix syntax, some missing features, system python dependency issues, high CPU usage, and lack of portability. People seem to suggest that xonsh is better for scripting than interactive usage.

Re: A shell colon does nothing. Use it anyway

#146
post #80

Well that's exciting. I learned a lot of uses for ":" today. However, the only one I already knew... if some-command; then : # command required else echo "command failed" fi I used to do that until I learned of if ! some-command; then echo "command failed" fi It's in the POSIX standard so it's not just a bashism: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V... > If the pipeline does not begin with the…

https://github.com/anordal/shellharden/blob/master/how_to_do...

Do you have a real-world example where we would like to preserve `$?` after the `if` (which `if` specifically branches on the result code of the command it tests)? Where we want to use the actual return code that the `if` did not handle itself.

I am asking because I have never needed preserving the `$?` outside of an `if`, nor have I ever seen this in somebody else's scripts, and I'm curious.

Re: A shell colon does nothing. Use it anyway

#147
post #145

One of the things I do with : is infinite while-loops, like: while :; do sleep n done Maybe to mainstream to make the cut!?

I prefer using "while true;" as that's easier to read. Arguably, it's less efficient due to calling the external "true".

Strangely though, I much prefer using the builtin "printf" to replace "echo" and "date", though the "date" usage is harder to read.

Re: A shell colon does nothing. Use it anyway

#149

Earlier quoted context omitted.

I feel the need to push back on this perspective. Old doesn't imply arcane. It instead can (and does, in this case) mean that it won out over the course of decades against other less worthy alternatives. Although you can write "programs" in sh, the shell syntax was never meant to be anything like a systems or application programming language. It was meant to efficiently automate systems tasks. It is kind of like the…

One of these are not like the other. Python is perfectly serviceable as a shell, to the extent that one could largely replace bash with the Python REPL if they wanted.

I'd be jumping out the top storey window after about 2 minutes of being required to use Python as a shell.

Python is a full-on programming language. Its REPL is a REPL for that language. Interacting with the OS and filesystem is a niche, tucked away in a corner of the language.

It has has none of the ergonomic affordances needed to be the user interface for interacting with files and processes.

Here are some simple commands:

    ls
    cd foo
    ls
    rm bar
    cd ../baz
    rm bar
    echo >readme.txt baz directory
    curl -s http://example.com >download
Let's try doing that with python:

    python
    >>> ls
    Traceback (most recent call last):
      File "", line 1, in 
    NameError: name 'ls' is not defined
    >>> import system
    Traceback (most recent call last):
      File "", line 1, in 
    ModuleNotFoundError: No module named 'system'
    >>> import os
    >>> os.dir.list()
    Traceback (most recent call last):
      File "", line 1, in 
    AttributeError: module 'os' has no attribute 'dir'
    >>> help(os)

    >>> os.listdir()
    ['foo', 'bar', 'baz']
    >>> cd foo
      File "", line 1
        cd foo
           ^
    SyntaxError: invalid syntax
    >>> chdir("foo")
    Traceback (most recent call last):
      File "", line 1, in 
    NameError: name 'chdir' is not defined
    >>> os.chdir("foo")
    >>> os.listdir()
    ['bar']
    >>> os.delete("bar")
    Traceback (most recent call last):
      File "", line 1, in 
    AttributeError: module 'os' has no attribute 'delete'
    >>> os.remove("bar")
    >>> os.chdir("../baz")
    >>> os.remove("bar")
    >>> f = open("readme.txt", "w")
    >>> f.write("baz directory")
    13
    >>> f.close()
    >>> import process
    Traceback (most recent call last):
      File "", line 1, in 
    ModuleNotFoundError: No module named 'process'
    >>> import subprocess
    >>> subprocess.run("curl", "-s", "http://example.com/")
    Traceback (most recent call last):
      File "", line 1, in 
      File "/usr/lib/python3.9/subprocess.py", line 505, in run
        with Popen(*popenargs, **kwargs) as process:
      File "/usr/lib/python3.9/subprocess.py", line 778, in __init__
        raise TypeError("bufsize must be an integer")
    TypeError: bufsize must be an integer
    >>> subprocess.run(["curl", "-s", "http://example.com/"])
    ...
    CompletedProcess(args=['curl', '-s', 'http://example.com/'], returncode=0)
    >>> subprocess.run(args=["curl", "-s", "http://example.com/"], capture_output=True)
    CompletedProcess(args=['curl', '-s', 'http://example.com/'], returncode=0, stdout=b'...\n', stderr=b'')
    >>> p = subprocess.run(args=["curl", "-s", "http://example.com/"], capture_output=True)
    >>> fh = open("download", "w")
    >>> fh.write(p.stdout)
    Traceback (most recent call last):
      File "", line 1, in 
    TypeError: write() argument must be str, not bytes
    >>> fh = open("download", "wb")
    >>> fh.write(p.stdout)
    559
    >>> fh.close()
Post reply on HN