Bash 5.0 released(lists.gnu.org) |
Bash 5.0 released(lists.gnu.org) |
$RANDOM yields a random integer in the range 0..32767. (This feature was already there.)
$EPOCHSECONDS yields the whole number of seconds since the epoch.
$EPOCHREALTIME yields the number of seconds since the epoch with microsecond precision.
I'm thinking of a new shell feature that would allow the user to define similar variables. For example, I have $today set to the current date in YYYY-MM-DD format, and I have to jump through some minor hoops to keep it up to date.
Does anyone else think this would be useful enough to propose as a new bash feature? Would it create any potential security holes? Should variables like $PATH be exempted?
(Of course this doesn't add any new functionality, since I could use "$(date +%F)" in place of "$today". It's just a bit of syntactic sugar.)
$ today() { date +%F; }
$ echo Today, $(today) is a great day!
Today, 2019-01-08 is a great day!I do have a workaround for this particular case:
PROMPT_COMMAND='today=$(printf "%(%F)T\n" -1)'
but it only works in bash 4.2 and later.I could use
PROMPT_COMMAND='today=$(date +%F)'
but I'm trying to avoid executing an external command on every prompt. (Maybe the overhead is low enough that it's not worth worrying about.)My thoughts are (a) if user-defined special variables like this were a shell feature, I could find other uses for them and (b) it seems neater to make such a feature available to users rather than restricting it to three special-case built-in variables.
On the other hand, it might have been cleaner for $RANDOM, $EPOCHSECONDS, and $EPOCHREALTIME to be implemented as built-in functions rather than as special variables.
On the plus side, TIL the subshell syntax plays well with eval/expand shortcut (ctrl+alt+e).
dualbus@system76-pc:~$ ksh -c 'date=; date.get() { .sh.value=$(date +%s); }; echo $date; sleep 5; echo $date'
1546926637
1546926642
See: https://docs.oracle.com/cd/E36784_01/html/E36870/ksh-1.html ("Discipline Functions")The problem is more with a language having fady bits and people using them when they don't make the code clearer, than with syntactic sugar.
I'm reminded of the Jargon file that says "Syntactic sugar causes cancer of the semicolon."
PROMPT_COMMAND='date=$(date +%D);time=$(date +%T)' $ PROMPT_COMMAND='time=$(date +%T)'
$ echo $time;date +%T
12:19:07
12:20:19
Thus it will show the time after your last command returned rather than the current time.Deploy a lambda function in multiple regions (15 regions!) with just one bash script using Apex up.
Add route53 on top with Latency Based Routing enabled and you've a latency in 10s of millsecond from anywhere on the globe without paying a hefty fee for this kind of latency.
As a scripting language, I loathe it and really don't understand its purpose. I always write shell scripts in POSIX shell for portability reasons. Most of the time I don't need to use any of Bash's features. In cases where advanced features are needed and portability is not a concern, there are other scripting languages much better suited for this (Python, Ruby, etc).
As an interactive shell, the only features I ever use are command history and tab completion. Bash is way too bloated for my use case (it's only a matter of time before the next Shellshock is discovered). Other lightweight shells are missing the couple of interactive features which I do use.
If anyone knows of a shell which meets my criteria of being lightweight but with command history and tab completion (paths, command names and command arguments), I'd really appreciate any suggestions. Otherwise I may have to look into extending dash or something.
I also had a storage controller go and had to figure out how to use shell builtins to create a tmpfs and reflash the firmware.
There are many reasons to provide builtins for basic file commands, from saving the extra process start to the tiny performance boost for scripts that should probably be using find instead.
It's a minor performance optimization that might be useful if you're doing thousands of rm's or stat's in a script.
That's probably a good sign you should advance from shell. If the script is trivial, it's going to be trivial in python / ruby / go / crystal / ... as well. If it's not trivial, that's another reason to move.
Alternatively - newer versions of ZSH are frequently provided by Apple.
brew install bashAt last!
> New features [...] BASH_ARGV0: a new variable that expands to $0 and sets $0 on assignment.
/bin/bash --version
GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin18)
Copyright (C) 2007 Free Software Foundation, Inc.
macOS used to be an awesome developer machine with good tools out of the box. Now the built-in tools are just a bootstrap for their own replacement via Homebrew. Like IE for downloading Chrome.Also- there is ammonite. Written for scripting.
bash is a programming language like any other, and you could use anything with a REPL as your shell. Python should do. In fact, I'll try it right now..
Yes, it works. Just sudo chsh -s /usr/bin/python <username> and off you go.
Once you start doing this for a bit, you'll notice that the Python REPL is an incredibly poor UI for repeated execution of subprocesses. It is very elaborate. Having to constantly wrap your strings in quotes, calling subprocess modules, exec, painstaking handing of streams, etc.
Then you start looking for a language that has better syntax for calling external programs.. hmm...
Bash. Or zsh, or ksh, etc. These languages excel at it. But that's all they are: programming languages that happen to be super easy to use when it comes to starting external programs.
This is why it makes little sense to bind them to the OS. As far as the OS is concerned: there is no Bash. Just like there is no Python. There is just syscalls.
Python REPL, even with recent additions of TAB completion, is a poor REPL, period.
IPython, on the other hand, offers a much better programming environment than shell while still allowing easy access to most of the things you mention. Example:
In [1]: from pathlib import Path
In [2]: file = Path("~/.sbclrc").expanduser().read_text()
In [3]: !echo "$file" | awk '!/^;;/' # EDIT: to clarify, this shows passing
# Python variable to a shell pipeline.
#-quicklisp
(let ((quicklisp-init (merge-pathnames quicklisp/setup.lisp
(user-homedir-pathname))))
(when (probe-file quicklisp-init)
(load quicklisp-init)))
All things considered, between !, %, %% and /, IPython is a decent shell. I was using it for a few years as my main shell, actually - its QT Console implementation specifically. I was working on Windows back then, PowerShell didn't exist yet, and `cmd.exe` was... well, exactly the same as today.TLDR: a shell is just a REPL with a few conveniences for specific tasks. Re-implement these and suddenly any REPL becomes a workable shell.
This 2013 thread shaped a lot of the way I think about Unix: https://news.ycombinator.com/item?id=6530180
Syscalls, in general, are used in lieu of objects or other abstractions because they more accurate mirror what the underlying hardware is doing. This isn't always the case, some syscalls are maintained for POSIX-compatibility and add a lot of complexity to emulate behavior that is no longer reflective of the hardware.
At the end of the day, you'll find that it's very difficult to maintain the highest levels of performance while also presenting an API that has a high level of abstraction. Things like dynamically-resizable lists, using hash tables for everything, runtime metaprogramming, and other such niceties of modern HLLs aren't free from a performance perspective.
If you really want to know more, I would suggest reading one of McKusick books on operating system design (the most recent being The Design and Implementation of the FreeBSD Operating System 2/e, but even the older ones are still largely relevant).
Maintaining this "useless POSIX compatibility trap" has a certain amount of utility; I for one like not having to re-write all of my programs every few years. I imagine others feel the same.
In closing, some projects that are pushing the boundaries of OS design which you may want to check out include:
* Redox OS (https://www.redox-os.org/) - a UNIX-like OS done from scratch in Rust
* OpenBSD (https://www.openbsd.org/) - one of the old-school Unices, written in plain old C, but with some modern security tricks up it's sleeves
* Helen OS (http://www.helenos.org/) - a new microkernel OS written from scratch in C++, Helen OS is not UNIX-like
* DragonFlyBSD (https://www.dragonflybsd.org/) - a FreeBSD fork focused on file systems research
* Haiku (https://www.haiku-os.org/) - binary and source compatible with BeOS, mostly written in C++, but also has a POSIX compatibility layer
What should one be using instead in the current scenario?
Python, Rust, Golang?
Exactly. Unfortunately.
Unless we have a solution that is significantly better than POSIX/UNIX, switching to anything else incurs a significant cost that no one is willing to pay.
Short of that, we probably need a technology breakthrough that brings in a complete architectural change.
The problem is that it doesn't even suffice for the new thing to be "significantly better". Because of the huge sunk cost, the new thing needs to be able to do desirable things that a POSIX-compatible OS strictly cannot do. Otherwise, it will always be easier and faster to just glue another subsystem onto the Linux kernel and continue using that.
You've already lost my interest. Bash/Shell is incredibly powerful and doesn't need a higher-level abstraction. That is what programming languages and CLI tools are for.
I would also love to know the answer to this question. I am a big fan of shells and shell programming in general and POSIX shell in particular.
Only suggestion I currently have is ksh, of which there are a few implementations, ksh93 still developed (https://github.com/att/ast), pdksh from OpenBSD (of which there is a portable version here: https://github.com/ibara/oksh) and MirBSD ksh (https://www.mirbsd.org/mksh.htm).
Otherwise of interest is mrsh: https://github.com/emersion/mrsh which was recently mentioned by Drew DeVault in a blog post linked here: https://news.ycombinator.com/item?id=18777909.
EDIT: And by mentioning mrsh, I meant it as a better/easier base to extend to get what you are asking for.
Unfortunately zsh and fish are more bloated than bash, and dash and ksh are missing the features I use.
I've just found "yash" which looks like a nice compromise. I'm going to give that a try.
(Personally, I use zsh, but it's much more heavy than tcsh.)
Given:
#include <stdio.h>
int main(int argc, char *argv[]) {
printf("Usage: %s [OPTIONS]\n", argv[0]);
return 0;
}
Running it as `./dir/demo --help` gives: Usage: ./dir/demo [OPTIONS]
Put it somewhere in $PATH, and run it as `demo --help`, and it will give: Usage: demo [OPTIONS]
Perfect!But with a Bash script, argv[0] is erased, it sets $0 is set to script path passed to `bash` as an argument.
Given:
#!/bin/bash
echo "Usage: $0 [OPTIONS]"
Running it as `./dir/demo --help` gives: Usage: ./dir/demo [OPTIONS]
So good, so far, since the kernel ran "/bin/bash ./dir/demo --help". But once we get $PATH involved, $0 stops being useful, since the path passed to Bash is the resolved file path; if you put it in /usr/bin, and run it as `demo --help`, it will give: Usage: /usr/bin/demo [OPTIONS]
Because the call to execvpe() looks at $PATH, resolves "demo" to "/usr/bin/demo", then passes "/usr/bin/demo" to the execve() syscall, and the kernel runs "/bin/bash /usr/bin/demo --help".In POSIX shell, $0 is a little useful for looking up the source file, but isn't so useful for knowing how the user invoked you. In Bash, if you need the source file, you're better served by ${BASH_SOURCE[0]}, rendering $0 relatively useless. And neither has a way to know how the user invoked you... until now.
It's a small problem, but one that there was no solution for.
Some pedantry: it's actually not. The argv array is a completely arbitrary thing, passed by the caller as an array of strings and packed by the kernel into some memory at the top of the stack on entry to main(). It doesn't need to correspond to anything in particular, the use of argv[0] as the file name of the program is a side effect of the way the Bourne shell syntax works. The actual file name to be executed is a separate argument to execve().
In fact there's no portable way to know for sure exactly what file was mapped into memory by the runtime linker to start your process. And getting really into the weeds there may not even be one! It would be totally possible to write a linker that loaded and relocated an ELF file into a bunch of anonymous mappings, unmapped itself, and then jumped to the entry point leaving the poor process no way at all to know where it had come from.
#!/bin/bash
echo "Usage: $(basename $0) [OPTIONS]"Changing argv[0] would make utilities like ps show a more descriptive/shorter name, eg in the case of long command paths.
And to do what you describe, there's `exec -a NAME' already:
$ (exec -a NOT-BASH bash -c 'echo $0; ps -p $BASHPID -f')
NOT-BASH
UID PID PPID C STIME TTY TIME CMD
dualbus 18210 2549 0 19:30 pts/1 00:00:00 NOT-BASH -c echo $0; ps -p $BASHPID -fYes, 2008.
I would generally describe a GNU/Linux distro as being a "giant pile of shell scripts". That's a little less true with init scripts generally now being systemd units. But that's where I'd start: Look at the code that distros write, that isn't part of some other upstream software.
- Arch Linux's `makepkg` https://git.archlinux.org/pacman.git
- Arch Linux's `mkinitcpio` https://git.archlinux.org/mkinitcpio.git/
- Arch Linux's `netctl` https://git.archlinux.org/netctl.git/
- Downstream from Arch, Parabola's "libretools" dev tools package https://git.parabola.nu/packages/libretools.git/ (disclaimer: I'm the maintainer of libretools)
Gentoo also has a lot of good shell scripting to look a, but it's mostly either POSIX shell, or targets older Bash (their guidelines http://devmanual.gentoo.org/tools-reference/bash/index.html say to avoid Bash 3 features). I tend to believe that changes made to the Bash language over the years are enhancements, and that they let you write cleaner, more robust code.
Read it! It's great. But know that a lot of bash scripting isn't really in bash, it's really required to be proficient with grep, sed, cut, dc and a few other text processing utilities. Learn those! Then are are a few other tricks to be mindful of: be mindful of spaces (wrap your variable substitution in double quotes, mostly), be mindful of sub-shells (piping to something that sets variables can be problematic), and a few other things that can really only be learned by reading good code.
But it's also good to know when you shouldn't venture further. My rule of thumb is when I'm using arrays or hash maps, then it's a good idea to move to another language. That's probably Python nowaways. A lot of people use tons of awk or perl snippets inside their bash scripts, that can also be a sign that it's time to move the whole script over.
If you have more logic than a couple of string comparisons, Bash is not the right tool for the job.
Like others say, "bash" is a hard tool to get right (and I'm not saying I do it right either, necessarily, but Greg's Wiki was real helpful!). I'm building a hybrid bash/python3 environment now (something I'll hopefully open-source at some point), and bash is just the "glue" to get things set up so most aspects of development can funnel through to python3 + other tools.
But ... things that make bash real useful:
* it's available everywhere (even in Windows with Ubuntu-18.04/WSL subsystem)
* it can bootstrap everything else you need
* it can wrap, in bash functions, aliases, and "variables" (parameters), the
real functionality you want to expose ... the
guts can be written in python3 or other tools
Without a good bash bootstrap script you end up writing 10 pages of arcane directions for multiple platforms telling people to download 10 packages and 4 pieces of software per platform, and nobody will have consistent reproducible environments.EDIT: I think there's a revised version of Greg's Bash Wiki in the works.
Python, sure, but replacing Bash with Node just seems like replacing a language crippled by its need to be backward compatible with (Bourne) sh with a language crippled by its need to be backward compatible with what Brandon Eich came up with in two weeks in 1995.
You're forgetting that bash really just calls other code. So you can combine two language's stdin/out functionality (eg, Python or Node) to pair code together. Sure, it won't be fast, but it can do quick wonders as an ad hoc data pipeline.
Keep them short. There are always exceptions but the "do one thing" mantra is handy, they can always be wrapped into a more complex workflow with a bigger script. None of my frequently used ones are over 100 LoC.
Write them for you and you alone when possible, start off simple and iterate. Fight that developer urge to solve a generalized problem for everyone.
Embrace the environment and global environment variables. We're trained to avoid global variables like the plague but they are really useful in scripts. My auto complete scripts that I mentioned above, they know which database to connect to based off the environment variable and there are separate commands to switch environment.
Make sure you aren't using it where things like make would be more appropriate.
* use traps http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_12_02.htm...
* read about safe ways to do things in bash https://github.com/anordal/shellharden/blob/master/how_to_do...
* this is pretty helpful writeup of general CLI usage, yet not bash specific https://github.com/jlevy/the-art-of-command-line (related HN discussion https://news.ycombinator.com/item?id=9720813)
https://tiswww.case.edu/php/chet/readline/readline.html#SEC1...
Readline is the library bash uses for editing the input line, and it has some nice movement keys. For example Alt-b moves the cursor back a word, Ctrl-u deletes to the beginning of the line, Ctrl-w removes one word behind the cursor.
They work in a bunch of other programs, like the Python interpreter's interactive mode for example.
Often, this is a good sign that you might want to switch to another scripting language.
also, https://www.shellcheck.net/ not reading, but pretty neat. static code analysis for shell scripts, points out common errors.
I would highly recommend BashGuide[2] and ryanstutorials[3] as a starting point. After that, go through rest of the wooledge site for FAQs, best practices, etc
shellcheck[4] is awesome for checking your scripts for potential downfalls and issues
[1] https://github.com/learnbyexample/scripting_course/blob/mast...
[2] https://mywiki.wooledge.org/BashGuide
I do think that if Apple can't ship a current version (for whatever reason), they probably shouldn't have it pre-installed at all, much like the BSD's don't come with bash by default either. Maybe they could ship with ksh/pdksh/mksh or something instead.
I assume that Apple's reasoning is similar.
Recent compared to bash maybe. 10.14's zsh is two years old.
I switched to zsh, personally - the one Apple ship is pretty current.
macOS is still a pretty solid developer machine.
(But it certainly suggests to me that macOS isn't actually the easiest out-of-the-box solution if your workflow includes anything more than web browsing.)
brew install bash
echo /usr/local/bin/bash | sudo tee -a /etc/shells
chsh -s /usr/local/bin/bash
and if you're on macOS and still haven't heard of homebrew, you first need to install it with /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"In practice, this approach often results in code that works only on Linux, or on Linux and macOS. I especially hate it when people shove #!/bin/bash as a shebang, and doubly so when it's in scripts that are a part of some npm package.
(On BSDs, Bash is not installed out of the box, and when it is installed, it's not in /bin, since it's not in the base system.)
Still, though, that's a good reason to stick to the original Bourne shell. Powershell, whatever its advantages may be, simply has too heavy dependencies on Linux, since you're dragging in CLR. At that point, like you said, might as well just use Perl or Python for scripting.
The problem with powershell as a scripting language, is it's designed to also be used as a shell. Which means, literals can be strings, function parameters are not separated, etc. It reminds me of Tcl in the 90s.
I really like what the powershell environment provides (like cmdlets, .NET) - but the language itself is dismal.
I would have preferred to have seen an existing scripting language, with .NET bindings added to it... the "NIH syndrome".
program | tee filename.txt &
It's also too verbose and needs too much shift for me to comfortably use as a shell. So why not just use a 'real' language if I'm going to write a script?
PROMPT_COMMAND='printf -v today "%(%F)T" -1'
printf's "-v" option was added in bash 4.0.printf's "%(...)T" format was added in bash 4.2.
The "-1" argument became optional in bash 4.3.
So here's what I now have in my .bashrc :
if [[ "$BASH_VERSION" > "4.2" ]] ; then
PROMPT_COMMAND='printf -v today "%(%F)T" -1'
else
PROMPT_COMMAND='today=$(date +%F)'
fi
(The "> 4.2" test is true for bash 4.2 and later, since the value of $BASH_VERSION for 4.2 is "4.2.0(1)-release". The ">" does a string comparison. I'll have to revisit this when and if there's a bash version 10.0, probably using $BASH_VERSINFO.)If the tasks performed by your program can be expressed maintainably and performantly in shell, go for it.
For programs one size up, something like Perl or Ruby or any other language that allows easy execution of shell commands can be a great solution.
Of course, this all depends on any number of variables. Team competencies, target environments, etc. And with some effort even larger bash scripts can be kept maintainable-ish, and in some target environments (can't always count on other languages being available!) shell scripts might be the only available programming environment.
My personal take on the book is that the kernel was meant to be a portable virtual machine, extensible through processes, and that those would be the building blocks of user applications for which the shell would act as glue.
In other words, the shell and the OS are separate because most of what we commonly call "the OS" may be interpreted as mere encapsulation of less versatile hardware architectures.
However, I wouldn't consider the second definition to be philosophical, but technical. It has more features than my needs, therefore it has more lines of code, potentially more bugs, uses more memory and has a greater attack surface.
Well... I know macros are supposed to be bad, but.. I've been programming in C for a long time, but only recently tried 'sugaring' my loops with
#define _(x,y) for (x=0;x<(y);x++)
..which has worked soo well, I'm sticking with it. It makes programming in C much more pleasurable. (My programs mostly have a lot of nested loops over multidimensional arrays, mostly from 0, inc'ed by 1)So now instead of e.g.
for (i=0;i<WID;i++)
for (j=0;j<HEI;j++) {
it's just _(i,WID) _(j,HEI) {
which makes me smile every time.I was on the fence about including ReactOS but wound up not including that either.
Python is the more direct substitute, though: it's built-in to almost every platform, and the Python 3 stagnation has even given us a consistent version: 2.7.
The tooling is just not there (old Python, old Perl, old Ruby and of course different versions from your deployment environment), you have to resort to third party tools such as homebrew or macports, you have to install Xcode to get gcc, you need an Apple ID to do that, the system level API is incompatibile with Linux, the filesystem is or at least was case insensitive. New MacOS versions after El Capitan are also getting worse at compatiiblity with other Unix-like platfroms. It's a pain to set up a development environment really, especially if you use any dynlibs. Instead of a VM we have a staging server where we deploy and there are almost always surprises.
In Linux the tooling is just there, a few seconds and one package manager command away. If your package is not there then there are PPAs or OBS repos. You can reproduce the platform you're deploying as closely as possible and there are less surprises.
Except you should really be in the habit of typing "cat ${today}" ;)
That's Bash (or at least sh). Which excels at piping the output of programs into other programs, and pay that cost for everything else.
It's actually the same philosophy that shells use: in bash you frequently invoke sed, awk, grep, etc. because it's easier than writing the same directly in the shell. In IPython, you invoke bash to do piping, because it's easier than connecting a host of subprocesses' stdins/stdouts in Python.
So again, there are some things you expect from your shell, and as long as you get those things (no matter how), you can use any REPL as a shell without problems.
[1] because of syntax or lack of library or something like that
Many Debian packages comes with a completion script for Bash so you get it when you install them :).
I prefer my version because it's easier for me to remember and read. I do use pattern substitution for other things, but I usually have to go to an interactive shell and create a test variable in order to remind myself whether I want # or %. I understand favoring built-in features over subshell calls for heavily used code, but I don't think this is especially critical for outputting usage info.
Why is that? Why don’t they build both from a single source?
This is the theory. The practice is that GNU mandates Texinfo for its projects, and because documentation tends to be the weak spot for all open source projects, manpages end up the most neglected as a result, which can be quite annoying. Especially since pretty much nobody else uses Texinfo - man pages are good enough for most console apps, and those that need more detailed documentation use Docbook, Markdown etc.
Typically (unless this changed at some point) the info pages are the canonical reference for GNU projects and the man pages are to accommodate Unix hackers.[1]
[1] https://www.gnu.org/prep/standards/standards.html#Man-Pages
I stand by my original statement: If you want to tell the user how to invoke the program again, argv[0] is the right thing. I didn't say that running argv[0] will necessarily actually invoke the program again, I said that it's the right thing to tell the user. If the caller set argv[0] to something else, it's because they wanted your program to believe that is its identity, so that's what it should represent its identity as to the user.
What if I invoke it from a distant path, do I want my 73 character long path to be prepended in the --help ?
Note that this is ISO C, not even POSIX. So ELF, Bourne shell etc are implementation details that are out of scope on this level.
Yes it does. This is a standard trick for changing the process name at runtime, several daemons do this to change the process name of child processes created by fork() that aren't separate executable. For instance, OpenSSH's sshd sets the child-process for a session to "sshd: USERNAME [priv]".
`exec -a` lets you set argv[0] through an execve() call, but many times you want to set it without exec'ing a new program.
Yes it does - that’s the whole point of changing it.
argv is a buffer in Bash's process memory space. This is AFAIK, not shared in any way with the kernel.
How would the kernel know that a process wrote to the memory location of argv[0] and then reflect that in /proc?
This is what I tried:
dualbus@system76-pc:~/src/gnu/bash$ ./bash -c 'echo $BASH_VERSION; ps -p $BASHPID -f; BASH_ARGV0=NOT-BASH; echo $0; ps -p $BASHPID -f; (ps -p $BASHPID -f && : do not optimize fork)'
5.0.0(1)-rc1
UID PID PPID C STIME TTY TIME CMD
dualbus 27918 20628 0 20:16 pts/5 00:00:00 ./bash -c echo $BASH_VERSION; ps -p $BASHPID -f; BASH_ARGV0=NOT-BASH; echo $0; ps -p $BASHPID -f; (ps -p $BASHPID -f && : do not optimize fork)
NOT-BASH
UID PID PPID C STIME TTY TIME CMD
dualbus 27918 20628 0 20:16 pts/5 00:00:00 ./bash -c echo $BASH_VERSION; ps -p $BASHPID -f; BASH_ARGV0=NOT-BASH; echo $0; ps -p $BASHPID -f; (ps -p $BASHPID -f && : do not optimize fork)
UID PID PPID C STIME TTY TIME CMD
dualbus 27921 27918 0 20:16 pts/5 00:00:00 ./bash -c echo $BASH_VERSION; ps -p $BASHPID -f; BASH_ARGV0=NOT-BASH; echo $0; ps -p $BASHPID -f; (ps -p $BASHPID -f && : do not optimize fork)https://github.com/torvalds/linux/blob/v4.20/fs/proc/base.c#...
https://github.com/torvalds/linux/blob/v4.20/fs/proc/base.c#...
Changing the `ps` output in a cross platform way requires a number of platform-dependent strategies, e.g. how PostgreSQL does it:
https://github.com/postgres/postgres/blob/REL_11_1/src/backe...
The kernel doesn’t need to monitor for reads - when proc reads it it’s read from the process.
It doesn’t need to be specially ‘shared’ with the kernel. The kernel can of course ready any memory it wants to from the process at any time.
I’ve implemented setting argv[0] in another language myself.
For me, the odds of that repo being compromised for long enough are outweighed by the convenience. This has been brought up on HN before and I'm not convinced.
I’m pretty sure at least 50% would merrily copy & paste it in their shell.
If /bin/foo is actually /nix/store/3508wrguwrgu3h5y9354rhfgw056y-foo-5.0/bin/foo, then when you run "foo", 0="/nix/store/3508wrguwrgu3h5y9354rhfgw056y-foo-5.0/bin/foo" and BASH_ARGV0="foo".
It really ought to be `#!/usr/bin/env bash` , if you're writing a bash script. That'll solve the location problem.
Otherwise, if it's a bash script, you can't get around needing bash on your system (although a great many bash scripts are actually "sh" shell scripts that just happen to specify bash because people are used to that sort of thing).
#!/bin/sh
Leave bash out of it tbh. In practice that will often end up being bash, but sometimes it won't be an in those cases you'll have yourself covered. Test it with busybox's sh or with dash, just to make sure.I wish it was well known. There are many people who don't even realize that Bash and Bourne shell are two different things. From there they assume that if their system runs it correctly, then it's portable.
$ brew install wireguard-tools
[1] - https://www.wireguard.com/install/Which, while you can do without, is a nice feature that makes some things easier.
dualbus@system76-pc:~$ cat argv0.c
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv) {
FILE *fp;
char buf[256]; // XXX :-)
strcpy(argv[0], "XYZ");
//puts(argv[0]);
fp = fopen("/proc/self/comm", "r");
fread(&buf, 1, 256, fp);
buf[255] = '\0';
puts(buf);
}
dualbus@system76-pc:~$ gcc -o argv0 argv0.c -Wall
dualbus@system76-pc:~$ ./argv0
argv0
dualbus@system76-pc:~$ python -c 'import sys; sys.argv[0] = "XYZ"; print(open("/proc/self/comm").read())'
python
dualbus@system76-pc:~$ ~/src/gnu/bash/bash -c 'BASH_ARGV0="XYZ"; cat /proc/$BASHPID/comm'
bash
Furthermore, https://github.com/torvalds/linux/blob/master/Documentation/... says: > 3.6 /proc/<pid>/comm & /proc/<pid>/task/<tid>/comm
> --------------------------------------------------------
> These files provide a method to access a tasks comm value. It also allows for
> a task to set its own or one of its thread siblings comm value. The comm value
> is limited in size compared to the cmdline value, so writing anything longer
> then the kernel's TASK_COMM_LEN (currently 16 chars) will result in a truncated
> comm value.
Which works as advertised: dualbus@system76-pc:~$ ~/src/gnu/bash/bash -c 'echo -n XYZ > /proc/$BASHPID/comm; ps -p $BASHPID'
PID TTY TIME CMD
28797 pts/6 00:00:00 XYZ
Can you show me an example, in any language, where updating argv[0] causes ps (or /proc/self/comm) to show the updated value?EDIT: formatting.
EDIT2: I stand corrected, see willglynn's comment.
To head off: it's not the patent grant. Apache 2 has a very similar patent grant and everyone is fine with it.
Edit:
Here is more information about that:
> Protecting Your Right to Tinker
> Tivoization is a dangerous attempt to curtail users' freedom: the right to modify your software will become meaningless if none of your computers let you do it. GPLv3 stops tivoization by requiring the distributor to provide you with whatever information or data is necessary to install modified software on the device. This may be as simple as a set of instructions, or it may include special data such as cryptographic keys or information about how to bypass an integrity check in the hardware. It will depend on how the hardware was designed—but no matter what information you need, you must be able to get it.
Source: https://www.gnu.org/licenses/quick-guide-gplv3.en.html
That means if there was GPLv3 code in iOS, Apple would have to send you their private keys to sign any source code so you can run it on iOS.
"The reason we can't ship modern Bash on macOS is that we're concerned we might accidentally include Bash on iOS."?
(and /bin/sh on macOS is already sufficiently user-modifiable to satisfy GPLv3)
OpenBSD apparently isn't fine with it, fwiw.
> The original Apache license was similar to the Berkeley license, but source code published under version 2 of the Apache license is subject to additional restrictions and cannot be included into OpenBSD.
> -- ref: https://www.openbsd.org/policy.html
I understand that you're well-intentioned, but I find the suggestion that I'm somehow not informed to be rather patronizing to be honest.
"There are restrictions!" "What restrictions?" "Everyone knows. It's patronizing to ask me. I won't say."
I use a separate tool to call a lot of functions written in C. That tool is called “Python”. Or “Ruby”.
Sometimes I use a separate tool to call functions written in Python (or JavaScript, or...) and that tool is called PostgreSQL.
Sometimes I use Ruby to call C to call Postgres to call JS.
> Now that we have better languages, why not use them to write the OS bottom-up?
What better languages for implementing an OS? Lisp? We had that before C. Rust? Either way—and I like both languages—I don't want to use either for a shell. Red? Maybe, but I don't think we're to the point of a Red OS yet, and while it's probably eventually usable for that purpose, I don't see it as necessarily ideal for OS implementation though it might be tolerable as a shell language.
There is a long history of alternative shells csh, tcsh, zsh, fish, etc. All with various level of abstraction and various amounts of "programming language type constructs" (for lack of a better term).
At the end of the day, long arguments have been had over which is the better shell. It's all just personal preference. Hence it can be set in /etc/passwd per user.
You prefer python? chsh is there to change it.
Space on a line is limited and one directional, so thr tools naturally evolved towards strange single line incantations instead of full fledged programs.
Commodore Pet did it right by introducing a navigable terminal where you could move between lines and don't need to open an editor to write multiline programs.
Modern CLIs can usually emulate at least a few of the old scrolling character matrix displays, but only a few bash commands (e.g. top) use the extra features.
I’m not saying POSIX shells are without fault but they weren’t just created because C is too low level; they were created because people used a terminal who weren’t always techies so Bell Labs created a language which anyone could easily write simple programs with. Granted that need has dissipated a little but your solution of having one language to rule them all creates more problems than it solves (really the only problem it solves is OCD for a few LISP enthusiasts).
The reason there are so many different programming languages isn’t just an element of NIH; some languages do genuinely handle some use cases better than some other languages. Plus there is always going to be an element of user preference. So your idea of a perfect system would be hell for a great many other people - myself included (and I do generally enjoy functional programming).
Compare Rust, which tries to keep allocations (and the size/asymptotic complexity of allocations) explicit and visible.
[1] The optimizer catches some cases, but not all of them.
Also, a quick look at the source tree shows there are still some other parts as well. GNU binutils, GNU diff, dialog is GPL, etc. See: https://github.com/freebsd/freebsd/tree/master/contrib
In the kernel, I think there are some drivers that are based on the Linux GPL code, for example: https://github.com/freebsd/freebsd/blob/1d6e4247415d264485ee... (just first hit from GitHub search for "gpl")
So yeah, looks like there's still plenty of GPL code in FreeBSD that's not trivially replaceable. The same applies to OpenBSD, although in general the OpenBSD people tend to be a bit more proactive in replacing GPL code.
I didn't include an entire summary of it, as it can be easily looked up on e.g. Wikipedia, as well as many other places.
At some point when I wasn't proficient enough in Bash yet, I was writing scripts for automation using Perl and Ruby. The 'logic part' is definitely much easier in these languages. But simple file/directory stuff is far more complex actually. A lot of this has to do with error handling and different expectations how that is supposed to work. In a default shell script, errors are handled very forgivingly which is very much how most people work when performing tasks manually - not every step is super important.
On the other hand Shell scripting documentation is crap. Most of it is from 80s/90s, full of irrelevant details for the practical person. A bit like 90s/00s JS documentation before MDN.
demo.c:
#include <unistd.h>
#include <string.h>
int main(int argc, char *argv[]) {
strcpy(argv[0], "frob");
sleep(100);
}
Terminal 1: $ make demo
cc demo.c -o demo
$ ./demo --greppable
Terminal 2: $ ps aux|grep greppable
luke 25858 0.0 0.0 2164 752 pts/0 S+ 00:32 0:00 frob o --greppable
luke 25931 0.0 0.0 8192 2356 pts/5 S+ 00:32 0:00 grep --color=auto greppable
$ cat -v /proc/25858/cmdline
frob^@o^@--greppable^@$ $ ruby -e "\$0 = 'im not lying to you'; sleep"
$ psFurthermore, it wouldn’t surprise me if iOS had bash support even for just debug builds and Apple either had to worry about testing, building and maintaining two version of bash and still risk getting them mixed up and accidentally shipping some parts of the bash source code. This much easier to just never use GPLV3
A Swedish copyright lobby organization committed copyright infringement on their own website. Bethesda game company had a trademark dispute with the developers of Minecraft. Apple and Samsung are constantly in patent war with each other. There is an almost unlimited number of cases where one company sue an other for contract and license disputes.
Shipping software is pretty dangerous, and there is no data to show that shipping GPLv3 licensed software is more likely to cause accidental infringement of someones IP than other licensed software.
I read the same argument about GPLv2 in like 1994. To date, there remains no case law I'm aware of where a copyright holder "lost" anything by "accidentally" shipping GPL software. How many decades does it take for us to put this myth to rest?
Anyway, with v2, the concerns were more vague - you'd have to accidentally link something GPLv2. With v3, even just shipping the binary signed with a private key on a platform that requires said key to load it, is enough to potentially force disclosure of that key (and that is by design of GPLv3 - it wants to kill the TiVo model).
But mm... why you would want to mutable state like current directory in first place? Or even mutable filesystem? Why aren't those just immutable parameters of your program?
Because that's how just about any OS, application, library, filesystem, device driver, database, nearly everything related to computing at all, works. Reinventing the universe has never, ever lead to success. If you want even the slightest hope for non-negligible adoption of your operating system, you need to be able to interface with the rest of the world. And that's why you don't want the filesystem to be an "immuatble parameter of your program".
> any OS, application, library, filesystem, device driver, database, nearly everything related to computing at all
-is trying to actually do to your files and operation like reverting changes is trivial. Sure it's not performance optimal and effects what kind of software is ideal to work within such a system. It's just a different approach with different trade-offs.
Anyway if I one day want to build new OS it's for trying different interesting approaches and not yet another 'successful any-OS'.
You can actually consider current directory as immutable already.
It became "badly mutable" for example if you manipulate the current directory and this change is observable from a program point of view which is already running. Would that be really useful?
To clarify I am not trying to say that absolutely everything should be immutable but it's fun thought experiment how far you can go.
Being immutable doesn't mean that everything is static but that things aren't changeable in place. So instead of having a global mutable state, you have this local state which you can alter by creating new instances and passing them around. In the end, the difference is that on what scope changes are observable and how that constraint effects on your design. In some sense: mutable = changes are uncontrollable, immutable = changes are controllable.
About termination, what you mention is kind of stopping further violation of the terms and maybe compensation for the past violations. What I wanted to mention (but wasn't at all clear about) is that after termination, you cannot even distribute if you intend to abide by the terms unless you are forgiven by the copyright holder. (In the case of the GPL version 3 there is some grace period during which for the first violation, if you abide within that period, you are explicitly permitted to resume distribution under the license terms.)
The big players in the industry did just that, and there appears to be a remarkable consensus on it.
Again, it's just stunning the extent to which this FUD hasn't changed at all over a quarter century.
Which is exactly what the GPL is! Especially v3.
That point is silly. If what you say were true, then the purchase would have been poison. It's not true. It's FUD. And it's hilariously the same FUD that people were flinging around in years before most of the existing FUD-flingers were even born.