DEV Community

Cover image for 🧠 How to Write Shell Scripts That Access Memory Safely
Francesco Bianco
Francesco Bianco

Posted on

🧠 How to Write Shell Scripts That Access Memory Safely

Rust became popular for one key reason: it made memory safety a core principle. In a world where a small mistake like a segmentation fault or a race condition can crash an application—or worse, open it up to serious vulnerabilities—Rust stepped up and said: ā€œNo more.ā€

But what about us? Those of us who write shell scripts every day to automate DevOps tasks, manage CI/CD pipelines, handle data, files, and processes? Do we have any tools that help us write "memory-safe" shell code?

Not quite like Rust. But we do have a few tools to make things better. One of the most underrated? The local keyword.


šŸ›”ļø Why local Is Important

In Bash, when you define variables inside a function, those variables are global by default. This means that your function can accidentally change the global environment even after it finishes.

Here’s a simple example:

#!/bin/bash

foo() {
  var="modified"
}

var="original"
foo
echo "$var"  # -> prints "modified"
Enter fullscreen mode Exit fullscreen mode

The function foo unexpectedly changed the global variable var. This can lead to hard-to-debug issues, especially in larger scripts or CI/CD environments with many functions.


šŸ” Use local to Contain State

The local keyword solves this problem by making a variable local to the function scope:

foo() {
  local var="modified"
}

var="original"
foo
echo "$var"  # -> prints "original"
Enter fullscreen mode Exit fullscreen mode

Just like Rust ensures memory isolation and ownership, local helps isolate variable state and prevent cross-function contamination.


āš ļø But Be Careful How You Use local

A very common mistake is doing this:

myfunc() {
  local myvar=$(some_command)
}
Enter fullscreen mode Exit fullscreen mode

This is not safe. If some_command fails, behaves unexpectedly, or produces weird output, it may interfere with the local declaration.

Also, ShellCheck (an amazing Bash linter) warns against this with:

SC2155: Declare and assign separately to avoid masking return values.

The correct, safe way is:

myfunc() {
  local myvar
  myvar=$(some_command)
}
Enter fullscreen mode Exit fullscreen mode

This separates the declaration (local myvar) from the assignment (myvar=$(...)), avoiding unintended behavior.


🧪 Practical Example

Let’s say you want a function that returns the size of a file in bytes:

get_file_size() {
  local size
  size=$(stat -c%s "$1")
  echo "$size"
}

file="example.txt"
echo "Size: $(get_file_size "$file") bytes"
Enter fullscreen mode Exit fullscreen mode

In this example:

  • size is local and won’t affect other parts of the script
  • The function is safe and reusable
  • You avoid unexpected side effects

šŸ”š Final Thoughts

No, local isn’t Rust. But in the world of shell scripting, it’s one of the best tools we have for writing modular, safe, and maintainable code. Using it correctly helps prevent bugs and makes your scripts more robust and predictable.

If you're writing scripts for DevOps, CI/CD, or system automation, make local your default when working with function variables. It’s a small habit that brings huge value.


šŸ’¬ Do you know other tips or patterns for writing safer, cleaner shell scripts? Share them in the comments! The more we exchange ideas, the stronger our scripting practices become.

Top comments (0)