首页 > 解决方案 > 在 shell 脚本中的变量名前插入“local”会导致错误

问题描述

这段代码(它是 shell 函数的一部分)完美运行:

    output=$(\
            cat "${vim_file}" | \
            sed -rne "${EXTRACT_ENTITIES}" | \
            sed -re "${CLEAR_LEADING_QUOTES}" | \
            sed -re "${NORMALIZE_NAMES}" \
    )

但是当我试图在作业前插入“本地”这个词时……</p>

    local output=$(\
            cat "${vim_file}" | \
            sed -rne "${EXTRACT_ENTITIES}" | \
            sed -re "${CLEAR_LEADING_QUOTES}" | \
            sed -re "${NORMALIZE_NAMES}" \
    )

…我收到一个奇怪的错误:

local: commands.: bad variable name

代码中没有错误的不可见字符:只有制表符在其他地方产生缩进和空格。该脚本以“#!/bin/sh”开头。在函数中的其他变量之前插入“local”不会导致任何问题。用另一个任意字符串替换“输出”(变量的名称)不会改变任何事情。操作系统是Linux。

标签: bashsh

解决方案


非常简短的回答:使用更多引号!

local output="$(\
        cat "${vim_file}" | \
        sed -rne "${EXTRACT_ENTITIES}" | \
        sed -re "${CLEAR_LEADING_QUOTES}" | \
        sed -re "${NORMALIZE_NAMES}" \
)"

更长的答案:双引号变量引用和命令替换几乎总是一个好主意。双引号可防止它们受到分词和文件名通配符扩展的影响,这很少是您想要的,并且可能会导致令人困惑的问题。

在某些情况下,去掉双引号是安全的,但规则令人困惑,难以记住,而且容易出错。这是那些令人困惑的案例之一。不会发生分词和通配符扩展的情况之一(因此可以安全地去掉双引号)是在赋值的右侧:

var=$othervar           # safe to omit double-quotes
var2=$(somecommand)     # also safe
var="$othervar"          # this also works fine
var2="$(somecommand)"    # so does this

一些 shell 将此扩展到作为命令一部分的分配,例如localor export

export var=$othervar         # *Maybe* ok, depending on the shell
local var2=$(somecommand)    # also *maybe* ok

bash 将这些视为一种赋值,因此它不会对值进行拆分扩展。但是 dash 更像是一个常规命令(其中参数确实被拆分扩展),所以如果你的脚本在 dash 下运行,它可能会遇到这样的问题。

例如,假设somecommand打印“export and local are shell commands”。然后在破折号中,local var2=$(somecommand)将扩展为:

local var2=export and local are shell commands.

...这将声明局部变量var2(设置为“export”)、andlocalareshell. 它也会尝试声明commands.为局部变量,但会失败,因为它不是合法的变量名。

因此,使用更多的引号!

export var="$othervar"         # Safe in all shells
local var2="$(somecommand)"    # also safe

或分开声明(或两者!):

export var
var=$othervar         # Safe in all shells, with or without quotes
local var2
var2=$(somecommand)    # also safe, with or without quotes

推荐阅读