$ a=1; b=1; c='!'; d='!'
$ [ "$a" = "$b" -a "$c" = "$d" ]
-bash: [: too many arguments
$ [ '!' '(' "$c" = "$d" ')' ]
-bash: [: `)' expected, found !
$ echo "${BASH_VERSION}"
5.1.4(1)-release
Note that it's not even a bug here; it's necessary for disambiguation. $ a=1; b=1; c='!'; d='!'
$ [[ $a = $b && $c = $d ]] && echo true
true
For anyone writing bash scripts today I would avoid the old test/[ functions entirely.I would call it a bug when there's one valid way to read it, and [ fails to see it. I don't see the ambiguation. For example, zsh's [ doesn't have these errors:
$ a=1; b=1; c='!'; d='!'
$ [ "$a" = "$b" -a "$c" = "$d" ]; echo $?
0
$ [ '!' '(' "$c" = "$d" ')' ]; echo $?
1
Same result with FreeBSD's tcsh's [.I think bash's [ is just lacking the ability to backtrack while parsing its arguments.
Curiously, GNU's [ fails to parse the arguments of the first, but not the second's:
$ command [ "$a" = "$b" -a "$c" = "$d" ]; echo $?
[: extra argument ‘!’
2
$ command [ '!' '(' "$c" = "$d" ')' ]; echo $?
1
It seems its argument parsing works differently when using parentheses: $ command [ "$a" = "$b" -a '(' "$c" = "$d" ')' ]; echo $?
0 [ x"$var" = x"val" ]
My eye doesn't have to separate "xval" into "x" and "val", so it's more obvious that the value being compared against is "val".(It behaves the same way since the shell allows quoting to start in the middle.)
http://www.oilshell.org/blog/2017/08/31.html
The POSIX spec did indeed make things cleaner; the last section quotes it and gives some style advice.
Moreover, similar problems are inherited by some programs that try to do shell-like commands but put their own syntax in the way. E.g. Ansible, where YAML, JSON, module call DSL and Jinja are all mixed on top of the commands so you can bump into any of them.
Actually re-reading your post you probably know that already! Nevermind then. Maybe someone reading this will be enlightened
At some point, "decades old idiomatic hack that increases robustness" stops being a hack and becomes an idiomatic way to increase robustness.
A better conclusion would be "yes, keep using it".
You know, shell scripts are a hack.
I really wish there was a middle ground between shell scripts and say python. Python has proper lists and hashes and loops and can manipulate paths with spaces or quotes or unicode. It doesn't get dragged down by the escape-an-escape-within-a-regex nonsense that makes things undecipherable. or ${VAR:-foo} or ${VAR##ugh}
But python is a bit fumbly when it comes to invoking external programs. try: ... subprocess.bleh except: ... ugh.
The exploit was based in inserting some \$\( make_a_new_root_account_in_etcpassw \) inside the variable inside the test.
As a result, both my friend and I stopped writing shell scripts as CGI and started learning perl just to do it.
Given i haven't spent a lot of time writing shell script yet but the syntax is just super weird, like I recently learned(1) that when you When you write if [ -e /etc/passwd ]; then .. that bracket is not shell syntax but just a regular command with a funny name.
Is there a recommended bash transpiler like what babel is to Js? So i can write bash scripts using a more coherent language and it spits out .sh files.
Perl may look ugly, but it doesn't have the escaping problems that Unix shells have. And most of the usual shell features (listing files, launching commands, etc...) are built-in. It is also available in almost all Unix systems, maybe even more so than bash.
My "favorite" (i.e. most terrifying) BASH fact is this: https://unix.stackexchange.com/questions/121013/how-does-lin...
Not suggesting it's suitable for everyone though. But it's certainly solved a lot of problems for me.
That’s how it used to be. Nowadays, most of the time it is a built-in, not it‘s own executable anymore.
It is a bit sad that his problem has to be encountered and resolved over and over and over again. Granted, it was a SIMPLE PARSER because resources were extremely tight. Note, I don't mean shells, I mean working with projects that implement parsers. As soon as someone busts out lex/yacc I know I'm going to see at least one "ah, we didn't think of that" issue. Parsers are hard.
So when test sees that one of its arguments is the string "-f", it has no way to know whether that string came from a variable like $var, a quoted string literal like "-f", or just the text -f. Most of the time if you're writing a parser for your own DSL you don't have this problem. You can tell the difference between the string literal "+" and the operator +.
They can be written in any compiled language you like or even an interpreted language, if you are prepared to add the dependency of an interpreter for that language at boot time.
This is a lot simpler than migrating to (and getting locked in to) systemd.
Oof. If people think JS is bad wait until they try to do anything moderately complex in shell script
For all the vaunted Unix Philosophy it's amazing how clunky some of it is. Countless shell scripts still trip over spaces in filenames. Of those that don't, nearly all of them will still be confused by any unusual characters like newlines. If you want something done properly, you have to pull out a proper scripting language, to have readdir() and the ability to pass arguments directly to a process.
Even Perl, which generally excels in such tasks has weird lapses in convenience. You can run a command with one line of code without the possibility of confusion with `system("ls", "-l", $dir)`, but you can't get its output that way. There's no version of `system` that'd allow you to both explicitly specify each argument to the process, and obtain its output. You either use backticks and risk quoting trouble, or need to use `open`, which is a lot more verbose.
It's interesting that it took Microsoft to do a new approach in this regard. PowerShell has its amount of weirdness I really hate, such as that the environment escapes the program into the commandline, but it's really refreshing how it dispenses with brittle grep, awk and cut stuff.
[ $X == "hello" ]
When X is empty, it gives: example.sh: line 5: [: ==: unary operator expected
So I fix it (apparently wrongly) with: [ x$X == x"hello" ]
I'll make a point of doing this instead: [ "$X" == "hello" ]Disclaimer: I am one of the current sponsors.
Maybe it is time to consider using rust instead: https://github.com/rust-shell-script/rust_cmd_lib ?