Passing arrays to bash functions

Short version: yes, you can pass an array to a Bash function. You can also manipulate the array contents within the function to pass information back. It is easy and has been supported since Bash version 4.3, I believe.

Long version: I recently watched a talk by some very knowledgeable people about Bash, where they delved deep into its internals and quirks. At one point, they discussed passing information to and from functions without creating subshells. The solution became quite convoluted, and I was surprised because the whole time I was thinking, “just use nameref“.

Out of curiosity, I searched online, but unfortunately, the internet is full of responses like “doesn’t work,” “Bash can’t do that” and many variations of “just pass all the values of the array to the function as arguments and piece them together again inside the function” (which is a terrible solution since you lose the keys). There are a few posts here and there suggesting local -n as a solution, but they are rare, and especially on sites like Stack Overflow, they are not the top answers.

In a nutshell what we are going to do is pass a reference to an array to a function (think “pointers” or “symlinks” if that helps).

Relevant parts of the bash man page for declare and local:

declare -n

Give each name the nameref attribute, making it a name reference to another variable. That other variable is defined by the value of name. All references, assignments, and attribute modifications to name, except for those using or changing the -n attribute itself, are performed on the variable referenced by name’s value. The nameref attribute cannot be applied to array variables.

local

For each argument, a local variable named name is created, and assigned value. The option can be any of the options accepted by declarelocal can only be used within a function; it makes the variable name have a visible scope restricted to that function and its children.

So, in summary, we can use local to define variables with a scope limited to the function they are defined in, and local accepts all the options that declare supports.

It seems the “The nameref attribute cannot be applied to array variables.” part of the declare definition causes a lot of confusion or deters people from trying to use it for referencing arrays.
What it means is that you can’t do a local -n my_array=() (i.e. applying the nameref attribute to an array), but local -n my_array is fine (where my_array is a variable with the nameref attribute which can also point to an array).

Enough theory, let’s get down to practical examples.

We will create a function called do_stuff that:

  • takes the name of an array as argument $1
  • reads the length key from the array
  • add a random key to the array with a random number the length of the length key previously read

Then we will create an array outside of the function with some keys/values, pass it to the do_stuff function, and then output the contents

So this shows us that the do_stuff function could read from the array (the length value), and write to the array (add the random number key/value), and the changes were applied to the array outside of the function. (where we did the declare -p). Bonus points for not needing a subshell.

Using this “trick” allows us to pass more complex information to a function, and especially receive more complex information from a function.

There is one caveat: you can’t use the same name for the array inside the function as well as outside. I wouldn’t advise doing this anyway for readability reasons, as the variable’s scope can become confusing. If you try it you get the following output:

Oddly I often noticed the following statement on Stack Overflow about nameref:

This only works if the array is defined as a global
Nope, works just as fine passing an array locally scoped to a function to another function this way.

(I prefer using a main() function like in this example to avoid global variables unless explicitly defined)

So, there you have it: an easy way to pass an array to a function in bash, no weird looping over values. And a better way to receive information from an array than the byte return value and parsing the output of the function.

Board game organizer for Dungeons & Dragons: The Fantasy Adventure Board Game

This is another board game organizer I made and uploaded to thingiverse. This time it is for the game Dungeons & Dragons: The Fantasy Adventure Board Game (BGG Link). My children really enjoy this game, so we sleeved the cards and I made some organizers so simplify setup and cleanup of the game.

 

Since it seems this game was mainly distributed in Europe in various languages, I also uploaded the SCAD files so you can translate the card names into other languages (the German version is uploaded as STL files).

The card boxes include space for the cards from the 2 expansions (forest and ice).

The box for all the heroes makes it easy to keep track of which character had which items between campaigns.

This isn’t intended as an insert for the original box.
Since I have both expansions, I use a bigger box to hold all the pieces.

Thingiverse Link with all the file downloads and printing instructions: https://www.thingiverse.com/thing:6034394

A case for the Pimoroni Tiny 2040

In my last post, I mentioned the Pimoroni Tiny 2040. While it probably won’t die by just dangling off it the end of a USB cable, or tossing the naked device it in your bag/pocket, I prefer to have a small case around it to have some protection and make handling easier.

This also has the benefit of looking more professional when using it at work, compared to the “uh, are you sure this is a good idea” look I get when plugging PCBs directly into USB ports.

The design itself is pretty basic:

  • as small as possible
  • a top and bottom half that snap together securely when assembled
  • a slight recession on the bottom to accommodate the parts on the underside of the PCB
  • holes for the two buttons
  • a thin layer above the LED so it is protected, but still can be seen/used

One reason I like using this case, is that I can print a few in different colors and switch them out based on the payload (e.g. red for dangerous, green/blue/yellow for safe, testing, informational).

 

 

 

 

I uploaded the design to Thingiverse for everyone to access: https://www.thingiverse.com/thing:5994359

 

Using the Pimoroni Tiny 2040 as a USB rubber ducky

Last year I bought a Pimoroni Tiny 2040 that I really enjoy playing around with. It’s a fun little device that runs Python. It’s about the size of a thumbnail, has an LED, and you can use the boot select button for user input.

(Image credit: Pimoroni)

 

I mainly use it as a cheap USB rubber ducky with a non-malicious script at work (if plugged into a PC, it registers as a keyboard and starts typing: open notepad, write some text about the importance of locking your PC, and then locks the PC).
To do this, install CircuitPython, and follow the instructions of this repository: pico-ducky

Once installed, you can easily write your own rubber ducky scripts and drop them on the device or use existing scripts found here: hak5/usbrubberducky-payloads

I have a small git repository that I use as a template to start off with, it includes all the required libraries and a slimmed down and modified rubber ducky parser: ryanschulze/rubber-pico-duck

The LED on the pico 2040 will glow dim blue when it has completed initialization and is ready, if you press the boot select button, the LED will turn red and it will execute the payload, when complete it will flash green briefly before returning to the ready state (dim blue).

 

Getting started with the Creality CR-6 SE 3D printer

I noticed an uptick in interest for the Creality 6-SE 3D printer lately (either because the price is dropped a bit end of last year, or because people are buying second hand). Since I’ve had mine since it was initially released on kickstarter, I thought I’d add some useful insights and links for people getting started with one.

My current CR6-SE setup

First off: it’s capable of making really consistent quality and precise prints for an FDM printer. That being said, the initial design and QA felt a bit rushed, and even if the newer models being produced now have fixed all the initial issues, there are still a few small things you should definitely do to upgrade the printer. For all the things I mention here, there are plenty of videos and more detailed information out there, google them if you are unsure or want more details.

Printing small minis
Printer calibration test

 

 

 

 

 

 

 

Unboxing Checklist

Ok, so you have the printer in front of you and are new to all this. Have a look at the following checklist to get it set up and make sure everything is working as intended: https://gist.github.com/Sebazzz/030d21c606413e22cbd77d8df9fb8b17

Firmware

The official firmware is a bit lacking in features and doesn’t make full use of the Marlin firmware it is based off. There is a community maintained firmware version that is far superior and add a lot of functionality and fixes: https://github.com/CR6Community/Marlin/releases

The firmware updates both the main motherboard and the firmware for the display.

Motherboard

Bigtreetech has a drop in replacement motherboard that also fixes a lot of the issues with the initial Creality motherboard. I’m using this motherboard and have been more than happy with it.

Alternative Motherboard from Bigtreetech

Daughterboard (Hotend)

If your hotend daughterboard breaks, it can be hard to find a replacement. What is sometimes easier to find is a complete hotend assembly (e.g. on aliexpress, it has the whole hotend assembly, strain gauge, daughterboard, hotend with heater and thermistor, fans and backplate).

Full Hotend Assembly

My tips

  • Don’t tie the ribbon cable to the hotend (black) and the bowden tube (white, filament moves through it) together. The hotend is connected to the strain gauge (which is used for the automatic bed leveling and triggers at around 160g of pressure if calibrated correctly). Pulling/pushing on the bowden tube can influence the sensitivity of the automatic bed leveling. This also means that if you make any modifications to the hotend assembly (especially to fans, cover or duct), you might have to recalibrate the strain gauge (there is a small potentiometer on the daughterboard on the hotend, it’s super finicky to adjust, I suggest using a kitchen scale and the LED should light up blue at around 160g).
  • Before you print anything else, print this filimant guide thing:4677617 it snaps in place between the extruder and the runout sensor and makes it infinitely simpler to feed filament into the system. Trust me, it’s a quick print and will make handling filament so much easier.

    Filament guide between runout sensor and extruder
  • If you want a quieter printer, replace the motherboard and power fans. I use Noctua versions of the fans (will need a step down from 24V to 12V for the motherboard fan), but any quiet fan will do. You will want to print an alternate cover for the psu that has space for the larger fan: thing:4665448. Since the fans extend farther down than the original design, you should also add/print risers to the feet of the printer to lift everything a few centimeters.

    Printed covers for motherboard and power supply
  • If you plan on updating firmware more regularly, you might want to extend the sdcard externally (so you don’t have to take apart the display to get to the display board each time). Just get a simple/cheap extender off amazon, you can either bring the cable outside at the bottom of the board, or through the ventilation slots on the back.

    External sdcard access to update display firmware
  • The standard glas printing surface is OK. I’ve also had good experience using the Creality PEI magnetic bed (has a rougher surface) and a magnetic WhamBam surface for a smoother finish.

 

Another list on reddit of helpful things to know: So you just ordered your CR-6 SE…

This should be enough to get you started 🙂