1. 55
  1.  

  2. 4

    I can not use FISH shell as it does not support such basic POSIX for loops as these:

    % for LOG in ls *.log; do tail -5 ${LOG}; done
    

    Its pointless to learn another new FISH syntax just for this …

    If it would support the I could try it and maybe switch from ZSH … but once you setup your ZSH shell there is no point in using any other shell then ZSH …

    1. 10

      Note that fish is focused on being an interactive shell, so, if you primary metric is how easy it is to write a for loop, you are looking at the tool of a wrong class.

      I personally use fish to type single-line commands in with out-of-the-box autosuggestions. If a need a for loop, I launch Julia.

      EDIT: sorry, I’ve misread your comment. The general point stand, but for a different reason: POSIX compat is a non-goal of fish.

      1. 1

        How would you do what vermaden did up there with Julia? Seems to me like a huge overkill, but then again if you’re sufficiently proficient with Julia, it might make sense.

        1. 3
          for log in filter(it->endswith(it, ".log"), readdir())
                 run(`tail -5 $log`)
          end
          

          The absence of globbing out of the box is indeed a pain.

          On the other hand, I don’t need to worry about handling spaces in param substitution.

          EDIT: to clarify, I din’t claim that Julia is better than zsh for scripting, it’s just the tool that I use personally. Although for me Julia indeed replaced both shell and Python scripts.

          1. 1

            IMHO that is a lot of pointless typing instead of just respecting the standards - like POSIX one.

            1. 4

              I agree that’s more typing! But pointlessness is in the fingers of typer, so to say.

              I personally don’t know bash — it’s too quirky for me to learn it naturally. Moreover, for me there’s little value in POSIX: I am developing desktop software, so I care about windows as well. For this reason, I try not to invest into nix-only tech.

              On the other hand, with Julia I get a well-designed programming language, which lets me to get the stuff done without knowing huge amount of trivia a la set -e or behavior of ${VAR} with spaces.

              There’s also an irrational personal disagreement with stuff that’s quirky/poorly designed. If I were in a situation where I really needed a low-keystroke shell scripting language, I am afraid I’d go for picking some un-POSIX lisp, or writing my own lang.

              1. 3

                To be honest, I find the snippet vermaden posted to already have lots of unessessairy typing. There’s no reason to use a loop if all you want is map commands to line. Xargs exists for this exact reason.

                But more to the point, what’s stopping you from calling Bourne shell whenever you need? Fish clearly states in its manual that it is not intended to be yet another scripting language, which in my opinion is an important and useful divide. I still write shellscripts all the time and have been a fish user for 10 years.

                1. 1

                  what’s stopping you from calling Bourne shell whenever you need?

                  Now you are maintaining TWO configurations for interactive shells.

                  My shell is where I command my computer. If I need, or am encouraged, to leave my shell to command my computer, my shell has failed.

              2. 1

                This would also work in Julia, is pretty short and shows how you can use patterns to find files (there’s Glob.jl, too, but I miss the ** glob from zsh):

                [run(`tail -5 $log`) for log in readdir() if contains(log, r".log$")]
                

                You might not know that endswith, contains and many other predicates in Julia have curried forms, so you could have written:

                for log in filter(endswith(".log"), readdir())
                    run(`tail -5 $log`)
                end
                
                1. 1

                  Thanks, I didn’t know about that!

                  Don’t you need \. in regex though?

                  1. 1

                    You’re welcome! And haha, yes, I should have escaped the dot :)

              3. 2

                Can’t speak for julia, but here it is in raku:

                dir.grep(/'.'log$/).map: *.lines.tail(5)
                

                Which is almost as concise as shell, and maintains more structure in its output.

              4. 1

                I write loops interactively in shell all the time. I wouldn’t consider a language suitable for interactive use as a shell if it lacked loops (or some other iteration mechanism).

              5. 10

                The syntax change is minimal:

                > for LOG in ls *.log; tail -5 $LOG; end
                

                Like mentioned in the sibling comment, any ad-hoc pipeline that gets involved should probably be a POSIX script for portability and reusability.

                The time commitment and fragility of a comparable ZSH setup is why I switched to Fish. Compare my .zshrc at 239 lines and my config.fish at 52 lines.

                1. 8

                  But what’s the advantage of the different syntax? Most people considering Fish will already be familiar with POSIX for loops. and will still be writing POSIX for loops for both shell scripts and for interactive shells on other systems. Is the extra “do” so annoying that it’s worth the extra overhead of constantly switching between the different shell for loop syntaxes?

                  This is literally the main reason why I’m not using fish. I appreciate the good out-of-the-box configuration. I’m painfully familiar with ZSH’s fragility; it even made me switch back to bash. I would love a good, modern, pretty, nice-out-of-the-box shell. I just don’t want to use a non-POSIX shell. When I’m just writing pipelines and for loops interactively, POSIX shell’s issues aren’t really relevant When I’m writing anything complex enough for POSIX shell’s issues to be relevant, it’s in a shell script in a file, and I don’t want all my shell scripts to use some weird non-standard syntax which will preclude me from switching to a different shell in the future. So fish’s “improved” syntax is a disadvantage for interactive use, and isn’t something I would use for non-interactive use anyways.

                  Also, the official documentation tells you to run chsh -s <path to fish> to switch to Fish. Well, large parts of UNIX systems expect $SHELL to be POSIX-compatible. If you follow the official documentation your Sway configuration will break, all Makefiles will break, your sxhkd config will break, and lots of other programs will break. If it’s going to recommend switching to Fish with chsh, it really should be POSIX compatible.

                  IMO, fish is an amazing shell made less relevant through insistence on having a syntax which doesn’t even remotely resemble POSIX shell syntax.

                  1. 11

                    Also, the official documentation tells you to run chsh -s to switch to Fish. Well, large parts of UNIX systems expect $SHELL to be POSIX-compatible. If you follow the official documentation your Sway configuration will break, all Makefiles will break, your sxhkd config will break, and lots of other programs will break. If it’s going to recommend switching to Fish with chsh, it really should be POSIX compatible.

                    This is simply not true. I use fish as my default shell and never had a problem with makefiles or my window manager, I use i3, but don’t know why sway would be different. I never encountered software that just runs scripts like that, they either have a #! line that specifies the shell or just call bash -c/sh -c directly or whatever.

                    IMO lack of Posix compliance in fish is a non issue, specially for experienced users which will know how to fallback to bash or write scripts and use #!. I used zsh for a long time and I’d use bash for scripts I could share with my team and everything just works. I feel like I could have switched to fish a lot sooner if I just tried instead of being put off by comments like these. If you are curious, just try it, maybe it’s for you, maybe it’s not, but don’t rely on other people’s opinion.

                    For me the biggest advantage of fish is I can easily understand my config. With zsh I had a bunch of plugins and configs to customize it and I understand almost none of it. Every time I wanted to change it I would lose a lot of time. Documentation was also a pain, searching for obscure features you had to read random forums and advice and try different things. fish has a great manual, and great man pages, everything is just easy to learn and lookup. I value that more than I value POSIX compliance, maybe you don’t, but form your own opinion.

                    1. 2

                      This is simply not true. I use fish as my default shell and never had a problem with makefiles or my window manager

                      I’m happy that you haven’t experienced issues. I know 100% for a fact that having a non-POSIX $SHELL was causing a lot of issues for me last time I tried using fish. Maybe you’ve been lucky, or maybe they have a workaround now.

                      For me the biggest advantage of fish is I can easily understand my config. With zsh I had a bunch of plugins and configs to customize it and I understand almost none of it.

                      That’s fine. I agree that the things you mention are advantages of fish. I was wondering what the advantage of a different syntax is. Like, in which ways would fish but with a POSIX syntax be worse than the current implementation of fish? In which situations is it an advantage to have a POSIX-incompatible syntax?

                      1. 3

                        There is the right and the wrong way to switch to fish: The right way is to set the login shell for a user (i.e. replace /bin/bash with /usr/bin/fish in /etc/passwd, either manually or with chsh).

                        The wrong way is to point /bin/sh at /usr/bin/fish: That, and only that symlink, is what matters to everything that implicitly invokes “the shell” (i.e. /bin/sh) without a hashbang, such as Makefiles. I’m not surprised at the carnage you described if you did this.

                        1. 3

                          I, too, used fish for a while and did observe breakage, and I for sure did not do anything as silly as that. I remember in particular this bug: https://github.com/fish-shell/fish-shell/issues/2292 After that I changed my shell to bash and did exec fish in .bashrc. This, IIRC, did fix most of the bugs, though I still had to be careful: some scripts don’t actually use a shebang and expect the shell to notice that the executable is a shell script.

                          For example:

                          $ echo echo 5 > x.sh
                          $ chmod +x x.sh
                          

                          Then, from bash:

                          $ ./x.sh
                          5
                          

                          And from fish:

                          Failed to execute process './x.sh'. Reason:
                          exec: Exec format error
                          The file './x.sh' is marked as an executable but could not be run by the operating system.
                          
                        2. 2

                          That’s fine. I agree that the things you mention are advantages of fish. I was wondering what the advantage of a different syntax is. Like, in which ways would fish but with a POSIX syntax be worse than the current implementation of fish? In which situations is it an advantage to have a POSIX-incompatible syntax?

                          That I don’t know. It’s possible that fish would be better if it was POSIX compatible, I was just saying that even though it is not POSIX compatible, it’s still worth using. I think fish syntax is better for interactive use than bash/zsh, but that is just my opinion. For script use I use bash anyway. One exception is when writing custom completions for my custom commands and then I am oh so grateful I am not using bash/zsh and not using that syntax.

                      2. 1

                        Could not agree more.

                        If one day FISH shell will also accept POSIX syntax for the while and for loops then I can look into it.

                      3. 3

                        I have tons of scripts but I also use these for and while POSIX loops all the time … and putting them in scripts is pointless because everytime its for different purpose or for different files or commands.

                        Besides I have made a syntax error and I can not edit my comment now :)

                        If should be either like that:

                        % for LOG in *.log; do tail -5 ${LOG}; done
                        

                        … or like that:

                        % for LOG in $( ls *.log ); do tail -5 ${LOG}; done
                        

                        I really do use these POSIX for and while loops interactively all the time, not sure that this serves as a proof but:

                        % grep -c -e 'for ' ~/.zhistory
                        522
                        
                        % grep -c -e 'while ' ~/.zhistory
                        653
                        

                        Thanks for sharing the ZSH config. Mines is at about 230 lines which 1/4 is for all shells variables like PATH or less(1) settings and 3/4 for ZSH itself.

                      4. 8

                        Is this flame bait? If you get over the syntax hurdle, there are many reasons why for loops with globs, especially interactively, are better written in fish:

                        1. Try typing this in your terminal, with newlines:

                          for LOG in *.log
                              tail -5 $LOG
                          end
                          

                          See? Who needs one-liners when you can have multiple in fish? This way, it stays easy to edit, read and navigate (2-dimensionally with the arrow keys) as you pile onto it.

                        2. In case your *.log expansion doesn’t match any file – compare this with any POSIX shell!

                          As a command argument…

                          ls *.log
                          

                          …and in a for loop:

                          for LOG in *.log
                              echo found $LOG
                          end
                          

                          As a command argument, fish prints an error, and doesn’t even run the command if the glob failed. In a for loop, the loop just iterates 0 times, with no error printed. In POSIX shelll, you can get either of these behaviours (by setting failglob or nullglob), but not both, which is a dilemma.

                        3. Recursive globs are on by default (not hidden behind the globstar flag) – who needs find anymore?

                          for LOG in **.log
                              echo found $LOG
                          end
                          
                        1. 4

                          Its not a troll attempt.

                          Its not my intention to force anyone to use ZSH or to discourage anyone from using FISH … besides I have made a syntax error and I can not edit my comment now :)

                          If should be either like that:

                          % for LOG in *.log; do tail -5 ${LOG}; done
                          

                          … or like that:

                          % for LOG in $( ls *.log ); do tail -5 ${LOG}; done
                          

                          I really do use these POSIX for and while loops interactively all the time, not sure that this serves as a proof but:

                          % grep -c -e 'for ' ~/.zhistory
                          522
                          
                          % grep -c -e 'while ' ~/.zhistory
                          653
                          
                          1. 3

                            one-liners

                            I don’t see how this is different from standard shell:

                            for LOG in *.log; do
                                    tail -5 $LOG
                            done
                            

                            This is how I usually write loops in scripts.

                            1. 2

                              It isn’t different. The command line behaviour is.

                              Can you type such a multi-liner ↑ at the command line, edit it all at once (not just one line at a time, with no turning back, as in Bash), and retrieve it from history in its full glory?

                          2. 4

                            I used zsh for a long time before switching to fish, and I basically found the interactive mode for fish to be a lot nicer—akin to zsh with oh-my-zsh, but even nicer, and faster. I absolutely switched for the interactive experience; most of my scripts are still written in bash for portability to my teammates.

                            The scripting changes make for a language that is a lot more internally consistent, so I have found that for my ad-hoc loops and stuff I do less googling to get it to work than I do using bash and zsh. Learning another shell syntax as idiosyncratic as bash would be very frustrating. At least with fish, it’s a very straightforward language.

                            If you are thinking about trying another shell, oil might be your jam, since it aims to be similar to POSIX syntax, but without as much ambiguity.

                          3. 1

                            Disclaimer: I admit in advance what I’m about to say runs afoul of the sunk-cost fallacy. … In the last year or so, I did a fairly deep reading of the Zsh manual and updated all of my system configurations. I’m reluctant to switch to a new shell.

                            For those in a similar position (like Zsh, have read the docs in some detail), any thoughts on switching? In particular, are there aspects in Fish that you would rather not live without? Are there aspects of Zsh that you miss after switching – or preventing you from switching?

                            1. 3

                              I was in a kind-of-dual position. Originally, I used fish. Then I switched to zsh, because it is more POSIX compatible, and I hoped to pick up shell scripting as I go. After couple of years with zsh, having realized that I still Google “bash if” every single time, I switched back to fish. This allowed me to delete my config, and get better autosuggestions (zsh equivalent wasn’t as good at that time).

                              If you are already comfortable with zsh, successfully configured autosuggestions and abbreviations, and don’t mind maintaining your config, there’s probably little reason to switch.