I find moving to even Python to be an inadequate answer, because the shell does two crucial things very very well - it manipulates the filesystem and runs commands in their most native format. And even Python is very cumbersome at those two tasks.
But sometimes you need good data structures/execution flow control, and good filesystem/command control, at the same time.
Intuitive, consistent, predictable whitespace handling would fix a lot of shell scripting problems, though.
(I haven’t given Powershell a serious shot, maybe I should.)
x = `{echo hi there: $user} # evalutates to list ('hi' 'there:' 'ori')
y = `:{echo hi there: $user} # evalutates to list ('hi there' ' ori')
There's no other word splitting, so: args = ('a' 'b c' 'd e f')
echo $#args
echo $args(3)
will print: 3
d e f
The shell itself is pleasantly simple; there's not much to learn[2]. And while it's not fun for interactive use on unix because it offloads too much of the interactive pleasantness to the plan 9 window system (rio), it's still great for scripting.Thankfully Perl exists.
In Perl, you can use backticks to execute commands for example
You can call pure python plus it has the simple running of command like other shells.
btw csh/tcsh "" quoting rules are atrocious, avoid it..
All it takes to understand it is that it took a while for anyone to consider that spaces in filenames was (or might be) a thing.
I don't know that this is true, but having started on Unix about the same time as the author of TFA, I know that I found it quite disorienting when I first started interacting with Windows/macOS users who regularly used spaces in their filenames and thought nothing of it.
I suspect this wasn't an "error" as much as just a failure to grok the pretty basic idea that "bite me.jpg" is an entirely valid filename, and maybe more useful than "biteme.jpg" or "bite_me.jpg"
If it's on the keyboard, they expect to be able to use it.
Course not have a hard separation between paths and file names is also not good.
./folder_what/folder_x/folder_zee:file_name.whatever
The above would be betterAt least most Windows users are "trained" by the Windows that asterisk, question mark, vertical bar, double quote, prefix and suffix spaces "aren't valid characters for files" (in a weird way, it's a Windows limitation, not a NTFS one). I expect only the worst (case insensitive stuff) naming schemes when the files comes from a macOS user.
Let's see what he says in this article:
- "$* is literally useless": no, it's used to covert arguments to a string separated by the first char in IFS. Useful pretty much only for logging, but sometimes joining strings. $@ is POSIX and should be used in all other cases. A niche feature that generally shouldn't be used isn't an issue in shell
- $* and $@ are the same except when $@ is quoted: true, except in more modern shells like bash, where $@ is an array, not a specially-treated variable. I don't know who told him to use $* for 35 years, but the author should be mad at them instead
- To make it work properly you have to say `for i in ; do cp "$i" /tmp; done`: wrong. cp can't distinguish arguments and flags. You must either use `./` or `cp -t /tmp -- "$i"` (or some variation). It's correct in the glob/wordsplit sense, but saying this is proper is incorrect
- "And the shell doesn't have this behavior for any other sort of special character": He doesnt even mention why spaces are magic. Hint: they aren't. It's entirely controlled by IFS, which you can change. The default is space, tab, and newline. He also doesn't mention globbing, which can arguably be more disasterous.
An article about wordsplitting and he doesn't even mention it once? This is at best a rant
I am grateful for all those who historically came up with the concepts and put in the work, but if anybody were to design a text interface to computers where things can be piped into other commands etc. today they could heavily improve the usability of the thing and safe thousands of collective hours wasted. And peobably like when trying to create a sucessor to email, nobody would use it.
Do yourself a favor and read Greg's entire wiki: https://mywiki.wooledge.org/BashFAQ and just learn how to use it properly, and then you can complain about how painful it is to learn or how easy it is to use incorrectly rather than how bad it is if you use it wrong.
`vidir [path]` will open an editor with the given directory as buffer contents. Editing and saving will translate to a sequence of `mv` invocations.
Requiring filenames to be quotes if they contain spaces, or optionally otherwise, would help – similar to CSV values with commas in. Though this opens up other issues: what about filenames containing quotes, and when nesting calls² the question of what part does the unpacking becomes a complex question without explicit structure. And to be honest we have enough trouble with clients sending us malformed CSV with unquoted commas that I can confidently state this wouldn't work either.
And you can't trust users to follow instructions, even internal users, where the limitation might be an issue. If you put a simple helper tool together and say “it won't work with spaces in filenames”, either it becomes a high priority ticket that the thing you jammed together as a favour doesn't work with spaces, or you get so sick or responding to problem reports that turn out to be due to the matter that you spend time fixing it up anyway. </rant>
--
[0] for systems that pass structured data, such as powershell, spaces are handled fine, though that would be a lot of work to retrofit into shells & utilities with a generally useful level of conformance
[1] like the convergent evolution of wings in pterodactyls/birds/bats or crab-like features all over the place
[2] for instance ssh to run a complex command line involving sudo
See https://drewdevault.com/2023/07/31/The-rc-shell-and-whitespa... to see the examples work out of the box as you woula naturally write them.
Not really, bash, fish and zsh all have arrays as "first-class data structures"; it's only really a problem if you really want to limit yourself to POSIX shell syntax.
Powershell's structured data can cause issues if you expect it to be similar to Unix-like shells.
For example, Powershell mangles piped binary data by default:
https://brianreiter.org/2010/01/29/powershells-object-pipeli...
Correct handling of piped binary data requires additional flags:
https://stackoverflow.com/questions/54086430/how-to-pipe-bin...
Get-Process | Out-Host -Paging | Format-List
Case sensitive hyphenated compound word commands?
There are some things shell does really well.
The real solution is something that does not split a variable on spaces, or that offers some control about how it splits things. These exist, there is no excuse to stick to bash in this day and age.
We really don’t need another layer of obfuscation between GUIs and the underlying file system.
First off, no, that's not a bug. The alternative is some variant of "here's a data structure to hold the list of arguments you need to manipulate manually". And that's how program execution works in "real programming language" environments (even things like PowerShell).
And it sucks, which is why we all continue to use the Bourne shell after four decades to solve these problems. What we really want is "here's a string to execute just like I typed it; go!". Sure, that's not what we think we want. And we might convince ourselves that mishandling based on that metaphor is a bad thing and write too-smart-for-our-own-good blog posts about it to show how smart we are.
But no, we don't want that. We want shell. If we didn't want shell, we wouldn't write shell scripts. And yet, here we are.
Again, four decades outweighs any amount of pontification in a blog post. If you aren't willing to start from a perspective of why this system remains so successful, you're probably not bringing as much insight to the problem as you think you are.
function backup {
local SOURCE=$1
local DESTINATION=$2
local ID_RSA=$3
# VALID_SSH is hard-coded for testing.
local VALID_SSH="yes"
local REMOTE_SHELL=""
if [[ "${VALID_SSH}" == "yes" ]]; then
REMOTE_SHELL='-e "ssh -i '${ID_RSA}'"'
fi
rsync -av \
--no-perms \
--links \
$(if [[ "${VALID_SSH}" == "yes" ]]; then echo "${REMOTE_SHELL}"; fi) \
"${SOURCE}" "${DESTINATION}"
}
As it is when calling the function: backup "." "backup@redstar.local:" "id_rsa"
rsync complains with: Missing trailing-" in remote-shell command.
rsync error: syntax or usage error (code 1) at main.c(438) [sender=3.1.3]
But if I echo the `rsync` instead of calling it, its output is perfectly valid it actually
runs as expected: rsync -av --no-perms --links -e "ssh -i id_rsa" . backup@redstar.local:
Been fiddling yesterday and today with no luck, it must be something very subtle. Tried a bunch of different things
from SO suggestions but none seem to work. Meh. RSYNC_ARGS='--progress --human-readable --human-readable'
if some_condition; then RSYNC_ARGS="$RSYNC_ARGS --exclude-from=some_file"; fi
rsync $RSYNC_ARGS foo bar
I can't think of a use for $* though and would guess it probably existed before $@ and is still there just for backwards compatibility.no such problems in bash.
You choose to expand a variable and then complain about not wanting the expansion?
Or about the behaviour of clearly documented special variables doing exactly what they're supposed to instead of something another special variable does? What are they unhappy about exactly, they don't like the symbol that was chosen??
These are all things you find out within minutes of reading the manpage. (one of the best written manpages out there, in fact).
Heck, this isn't even a "cannot whitespace" problem. It's expanded vs unexpanded tokens. Which is a feature of the language. Because it's text/stream based (not "despite"). 35 years of shell experience? I call bait.
Curious to read this article when it recovers from the HN load.
Joking aside, as a relatively newbie to the star nix world and liking it - shell scripting in Linux/Unix is broken.
The object handling approach that powershell provides just seem to be a better approach.
Bell Labs fixed it with the shell called “tc”. They can’t be blamed that you ignored it.
> mv "$i" $(suf "$i").jpg # two sets of quotes
> done
Doesn't this need another set of quotes, `mv "$i" "$(suf "$i")".jpg`, or else it'll just fail in a slightly different way when asked to `mv "bite me" bite me.jpg`?