只有在variables非空时才引用

我有一个古老的bash脚本,我想改进。 这个脚本使用了许多variables,在某些情况下,一些variables被引用,但是是空的或者是未设置的。 这通常不是一个问题,因为脚本从一开始就是这样devise的。

不过,我已经开始使用shellcheck ,它抱怨失踪报价很多。 所以我添加了引号,并且遇到了一个不便,我没有一个很好的解决scheme。

有很多行看起来像这样:

cmd $param1 $param2 $param3 $param4

如果其中一个参数是空的或未设置的,它仍然在工作,cmd获得的参数数量减less。 但是,如果我开始添加引号

cmd "$param1" "$param2" "$param3" "$param4"

cmd总是会得到4个参数,不pipe它们是否为空。

为什么这是非常清楚的。 解决方法也是清楚的(在使用param之前检查是否为空),但是它很丑,需要大量额外的代码。

所以我正在寻找聪明的解决scheme,要么a)省略一个参数(包括引号!),如果它是空的b)添加引用只为非空variables

你用这个脚本的shell是什么? 我假设它是/ bin / sh

在POSIX shell中唯一的类似数组的实体是位置参数。 你可以这样做:

 set -- # clear the positional parameters for param in "$param1" "$param2" "$param3" "$param4"; do if [ -n "$param" ]; then # append this param to the positional params set -- "$@" "$param" fi done # invoke the command with the positional params, properly quoted cmd "$@" 

如果你想弄清楚它,请将cmd的调用包装在一个函数中:

 invoke_cmd() { n="$#" # remember the original number of params # append to the args list only if non-empty for arg; do [ -n "$arg" ] && set -- "$@" "$arg"; done # discard the original params (including the empty ones) shift "$n" # and invoke the cmd cmd "$@" } invoke_cmd "$param1" "$param2" "$param3" "$param4" 

对于实际的bash,简化

 invoke_cmd() { local args=() for arg; do [[ "$arg" ]] && args+=("$arg"); done cmd "${args[@]}" } invoke_cmd "$param1" "$param2" "$param3" "$param4" 

另一个选项(除了@glennjackman所描述的)是使用条件扩展:+只有在被设置和非空时才包含一个(正确引用的)variables:

 cmd ${param1:+"$param1"} ${param2:+"$param2"} ${param3:+"$param3"} ${param4:+"$param4"} 

(注意:条件扩展在2.6.2的posix规范中;但是我不能完全确定所有的posix shell都会正确地遵守备用值中的双引号)。

如果您愿意对脚本进行更广泛的更改,并将其限制为bash(即,如果您正在使用#!/bin/bash#!/usr/bin/env bash shebang),则通常会更清晰在数组中累加参数:

 cmd_parameters=() # start with an empty array if [ something ]; then cmd_parameters+=("$param1") # Add an element -- note that the () are critical here! fi if [ something_else ]; then cmd_parameters+=("$param2") fi ...etc cmd "${cmd_parameters[@]}" 

请注意,完全可以将这些方法混合使用,包括使用:+技巧来有条件地添加数组元素:

 cmd_parameters+=(${param3:+"$param3"}) 

和/或将数组和条件参数混合到相同的命令中:

 cmd "${cmd_parameters[@]}" ${param4:+"$param4"} 

另外,玩@ glennjackman的包装函数的build议,它可能会写一个通用的包装函数:

 conditional_args() { # invoke a command ($1) with any empty arguments omitted args=() for arg; do args+=(${arg:+"$arg"}) done "${args[@]}" # Note that the first "arg" is actually the command itself } conditional_args cmd "$param1" "$param2" "$param3" "$param4"