Best Practices for Command Storage in Shell Scripts: From Variables to Arrays and Functions

Nov 22, 2025 · Programming · 10 views · 7.8

Keywords: Shell Scripting | Command Storage | eval Risks | Array Variables | Function Encapsulation

Abstract: This article provides an in-depth exploration of various methods for storing commands in Shell scripts, focusing on the risks and limitations of the eval command while detailing secure alternatives using arrays and functions. Through comparative analysis of simple commands versus complex pipeline commands, it explains the underlying mechanisms of word splitting and quote processing, offering complete solutions for Bash, ksh, zsh, and POSIX sh environments, accompanied by detailed code examples illustrating application scenarios and precautions for each method.

Problem Background and Challenges

In Shell script development, there is often a need to store commands in variables for later execution. Beginners typically attempt to directly assign command strings to variables, which works correctly in simple cases but encounters issues when commands contain pipes, redirections, or spaces.

Basic Examples and Problem Analysis

Consider the following simple command storage example:

command="ls"
echo "Command: $command"
b=`$command`
echo $b

This code executes correctly, outputting the file list of the current directory. However, when attempting to store more complex commands:

command="ls | grep -c '^'"
$command

The system reports an error: ls: cannot access |: No such file or directory. This occurs because Shell performs word splitting after variable expansion, treating | and grep as filename arguments to the ls command rather than as pipe operators.

eval Command Solution and Risks

Using the eval command can resolve this issue:

x="ls | wc"
eval "$x"
y=$(eval "$x")
echo "$y"

eval performs complete Shell parsing of the string, including processing of special characters like pipes and redirections. However, this method poses significant security risks, particularly when command strings include user input:

read -r filename
cmd="ls -ld '$filename'"
eval "$cmd"

If the user inputs '$(rm -rf /)', the single quotes will be escaped, causing command substitution execution that could potentially damage the system.

Secure Array Storage Solution

In Shells that support arrays (Bash, ksh, zsh), using arrays is a safer alternative:

cmdArgs=('ls' '|' 'grep' '-c' '^')
"${cmdArgs[@]}"

Each array element remains independent, avoiding word splitting issues. Array contents can be viewed using declare -p:

declare -p cmdArgs
declare -a cmdArgs='([0]="ls" [1]="|" [2]="grep" [3]="-c" [4]="^")'

Dynamic Command Parameter Construction

The array method supports flexible parameter construction:

mycmd=('ls')
if [ "$want_detail" = 1 ]; then
    mycmd+=('-l')
fi
mycmd+=("$targetdir")
"${mycmd[@]}"

This approach is particularly suitable for scenarios requiring dynamic adjustment of command parameters based on conditions.

Function Encapsulation Solution

For fixed complex commands, using functions provides the clearest approach:

cmd() {
    ls | grep -c '^'
}
cmd

Commands within functions are parsed and executed only upon invocation, avoiding preprocessing issues while offering better code organization and readability.

POSIX Compatible Solution

In Shells supporting only POSIX standards, positional parameters $@ can be used:

set -- ls '|' grep '-c' '^'
"$@"

Although the syntax is somewhat cumbersome, this method offers excellent compatibility.

Practical Application Examples

Consider a complex curl request scenario:

payload='{}'
hostURL='http://example.com'
authToken='someToken'
curlCMD=('-X' 'POST' "$hostURL" '--data' "$payload" '-H' 'Content-Type:application/json' '-H' "Authorization:Bearer $authToken")
curl "${curlCMD[@]}"

This method ensures correct passing of each parameter, including header values containing spaces.

Technical Principle Deep Analysis

Shell command execution involves multiple processing stages: parsing, expansion, word splitting, and filename generation. When commands are stored in variables, variable expansion occurs after word splitting, causing special characters to lose their syntactic meaning.

Array and function methods remain secure because they maintain separation of command elements until actual execution, when complete command assembly occurs. This approach avoids additional parsing layers, reducing security vulnerability risks.

Best Practices Summary

Based on the above analysis, the following command storage strategies are recommended:

Combining these methods enables the construction of both secure and flexible Shell scripts adaptable to various complex command execution requirements.

Copyright Notice: All rights in this article are reserved by the operators of DevGex. Reasonable sharing and citation are welcome; any reproduction, excerpting, or re-publication without prior permission is prohibited.