我有一个古老的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"