Wandering Thoughts archives


The Bourne shell lets you set variables in if expressions

Today I was writing some Bourne shell code where I wanted to run a command, gather its output (if any), and see whether or not it succeeded. My standard form for this is:

res="$(... whatever ...)"
if [ "$?" -eq 0 ]; then ...

(I could potentially use a pipeline to process the command's output, but there can be reasons to capture the output. Here I deliberately don't want to process any output the command may produce if it reports that it failed.)

When I ran my script through shellcheck (as I always do these days), it reported SC2181, which is, to quote:

SC2181: Check exit code directly with e.g. 'if mycmd;', not indirectly with $?.

This isn't the first time I've seen SC2181 and as always, I rolled my eyes at it because it seemed obviously wrong, because of course you can't merge these two lines together. But this time I went off to the Shellcheck repository to report it as an issue, and before I reported it as an issue I did a search, and that was when I discovered that Shellcheck was not wrong.

To my surprise, the Bourne shell allows you to perform command substitutions and capture the output in variables in if expressions. You really can write my two lines in a single one as:

if res="$(...)"; then

You can even set variables to ordinary values if you want to, but 'var=$value' normally or always has an exit status of 0 so it's not very useful to put it in an if expression.

Despite this transformation being possible, I opted not to do it in my case because my command substitution was for a rather long command. In my opinion, it's just as wrong for readability to write:

if res="$( ... giant long command line ...)" ; then

as it would be to write a similar thing in C:

if (res = ptr->someLongFunction(with, many, arguments, that, sprawl)) {

In both cases things are much more readable and clear if you put things on two lines instead of trying to jam everything on one line. The Bourne shell should be written the way I initially did, and the C should be:

res = ptr->someLongFunction(with, many, arguments, that, sprawl);
if (res) {

Just because you can jam the two things together on one line doesn't mean that you should. Sometimes it's clearer on one line and sometimes it isn't.

(Of course ideally you wouldn't have so many arguments to a C function call. Unfortunately long command lines can be unavoidable in shell scripts, because some commands have very verbose options.)

(This elaborates on a tweet of mine, and also on the Fediverse.)

PS: This isn't the first Shellcheck warning that I routinely ignore.

programming/BourneIfCanSetVars written at 23:04:21; Add Comment

Firefox and the challenge of trying to make visited links clearly visible

I tweeted:

I wish I could work out a way in the Stylus Firefox addon to force-style visited links in something distinctive. In theory it's easy; in practice Firefox seems to sharply limit how you can style them these days for privacy, and my attempts so far aren't all that successful.

I frequently read articles on the Internet that have plenty of links to other interesting things, some of which I've read and some of which I haven't and would like to. On normal websites, this is what my very large browser history and the default visual distinction between visited and unvisited links is good for; it tells me what things I haven't read yet. Unfortunately, a steadily increasing number of websites style unvisited and visited links the same, defeating my attempts to see what I've already read. Sometimes they go the extra distance to style links so it's hard to even tell they are links.

With suitable effort, I could definitely use Stylus to create individual styles for every annoying site that made unvisited links have a distinctly different colour the way they're supposed to. But that's a lot of work. What I'd prefer to do is create a single global style, normally not on, that would make unvisited links (and perhaps visited ones) stand out no matter what colours and CSS styling the particular site was already using.

In the old days, this would have been pretty simple. There are a lot of text styles that aren't used much and stand out a lot, such as strike-throughs or heavy underlines. The result wouldn't necessarily look the best, but at least I could see what links I'd already read. Unfortunately, you can't do that any more (for good reasons). These days, only a few things can be set on the CSS :visited selector, mostly colour changes. Changing and setting colours in general is dangerous, especially in a world where so many websites already set them to various unpredictable values that may not be distinct from my new ones.

Given the limitations on what you can set on :visited, I most likely need both an overall distinctive style for a:link and then a complementary modification for :visited. While MDN's Styling links has given me some things to think about, I currently haven't come up with a good styling combination that actually works.

(In the process of poking around MDN, I did discover that in Firefox you can now access the standard colours of visited and unvisited links with the special colour names of LinkText and VisitedText.)

web/FirefoxSeeVisitedLinks written at 00:57:59; Add Comment

Page tools: See As Normal.
Login: Password:
Atom Syndication: Recent Pages, Recent Comments.

This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.