【问题标题】:variable in a script is not seen inside the script (csh, tcsh)在脚本中看不到脚本中的变量(csh、tcsh)
【发布时间】:2018-04-14 10:51:24
【问题描述】:

我想设置一个指示目录的变量,并使用它来访问该目录中的文件。
所以我写了一个简单的脚本(注意我没有把#!/bin/csh放在前面)

文件测试:

set dir1=/tmp
ls -l $dir1

我执行了chmod +x test 并运行了test,但它只显示了我当前的目录,例如 $dir1 只是空的。我尝试使用 {XX} 无济于事。

我想在不使用 #!/usr/bin/env tcsh 或 #!/bin/csch 或 #!/bin/tcsh 的情况下执行此操作。这是不可能的吗? (我不想启动一个新的 shell,但使用相同的别名和其他以前的环境变量等)

怎么了?我在 tcsh 中这样做。

添加

后来发现

dir1=/tmp
ls $dir1

就是答案。

【问题讨论】:

  • linux 中的'set' 命令与 Windows 不同!
  • ls 命令不是您的 shell 内置的。 dir 命令也没有内置到您的 shell 中。如果您的问题是关于 csh 变量设置和扩展,那么将 ls 更改为 dir 并不是真正的答案的一部分……跳过 shebang 并不能避免运行新的 shell。在 csh/tcsh 中的 shell 中执行内联命令的方法是使用 source 命令。
  • 另外,为什么这个问题被标记为 bash
  • @ghoti 如果我想给它一些论据怎么办? (我想将它与 $1 $2.. 一起使用)使用 source 我不能给出论据,可以吗?
  • @ChanKim - 如果你想给一个脚本参数,你就是在暗示一个新的 shell 来运行那个脚本。听起来您真正想要的是 tcsh 中的 alias(或 POSIX shell 或 bash 中的 function)。

标签: bash csh tcsh


【解决方案1】:

请注意 shell 变量环境变量 之间的区别,shell 变量 可以交互使用,也可以在脚本中使用,但对脚本来说是本地的到脚本调用的程序。

在 POSIX(或 bash 或相关)shell 中,您可以使用 export 内置命令将 shell 变量转换为环境变量。

在 csh/tcsh 中,set 命令设置一个 shell 变量,但setenv 命令设置一个环境变量。设置后,您可以像使用 shell 变量一样在 shell 脚本中使用环境变量,但该变量将包含在子 shell 或您运行的其他程序的环境中。

注意:

1% set foo=bar
2% echo $foo
bar
3% csh
1% echo $foo
foo: Undefined variable.
2%

1% setenv foo bar
2% echo $foo
bar
3% csh
1% echo $foo
bar
2%

在第一个示例中,set 命令创建了一个 shell 变量,该变量仅在设置它的 shell 的上下文中可见。在第二个示例中,setenv 命令创建了一个 environment 变量,该变量被传递给子 shell。

请注意,通过脚本中的任一方法设置变量 将不允许将该变量传递回调用shell,正如您在使用使用花括号的POSIX shell 函数时所看到的那样。对于 csh/tcsh 中的那种功能,您可能不得不依赖 alias 命令。例如,我使用以下别名:

alias go 'cd `dirname \!:*`'

这让我可以这样做:

1% alias go 'cd `dirname \!:*`'
2% go /usr/local/etc/foo.rc
3% pwd
/usr/local/etc
4%

查看man tcshHistory substitution 部分,了解其工作原理。

如果您尝试构建一个依赖于传递回父 shell 的信息的解决方案,请使用不同的 shell,或者在您编写的命令以及别名上使用带有 stdout 的反引号替换。

【讨论】:

  • 这个答案更中肯,所以我选择这个作为答案。 :)
【解决方案2】:

简短回答:根据您的 cmets,您需要使用 source 命令运行脚本(请参阅 @ghoti 的评论)。

长答案:运行 shell 脚本有多种不同的方式,它们的运行方式具有不同的含义。

  • 运行脚本的正常首选方式是让脚本以 shebang (#!) 行开头,指定要用于它的解释器(/bin/sh、/bin/bash 等),然后将脚本放在路径中的目录中并按名称执行它,或者指定脚本的路径作为命令(注意./scriptname 是这种情况的一种特殊情况,路径为“就在此处”)。

    使用此方法,将创建一个运行指定解释器的子进程并执行脚本。由于脚本在子进程中执行,因此其中设置的环境变量等内容不会影响运行它的 shell 的环境(即设置 dir1=/tmp 仅适用于脚本内,而不适用于脚本完成后)。

  • 如果脚本没有 shebang,您也可以按名称或路径运行脚本。这也创建了一个运行一些解释器的子进程(其中一个有点废话)。没有充分的理由这样做;使用shebang。

  • 您可以通过显式调用解释器来运行脚本,如sh /path/to/scriptbash /path/to/scriptcsh /path/to/script。请注意,如果脚本在当前目录中,则不需要完整路径;它的名字就足够了。这也会在子进程中运行脚本,但使用指定的解释器(如果有则忽略 shebang 行)。

    如果您指定了错误的解释器(例如,将sh 用于仅使用 bash 功能的脚本),此选项有时会导致问题,并且仅应在某些情况阻止您使用第一个选项时使用。

  • 最后,您可以使用source 命令运行脚本(例如source /path/to/scriptsource scriptname,如果它在当前目录中)。与其他人不同,这不会创建子流程;它告诉当前 shell 从文件中执行命令。这意味着脚本最好以适合您当前 shell 的语法编写;如果你 source 来自 csh 或 tcsh 的 bash 或 sh 脚本,它不会顺利进行。这也意味着shebang(如果有的话)被忽略了。

    如果您希望脚本中的环境变量定义在您运行脚本的 shell 中可用,这是唯一的方法。 (嗯,除了在类似 sh 的 shell 中,您可以使用 . 命令,因为这是 source 的同义词。)

    由于脚本为sourced 时任何shebang 行都会被忽略,因此您可以包含或不包含它。我倾向于在应该是 sourced, either giving the correct interpreter as a hint to users, or using a#!/bin/echoshebang to print a message if someone tries to run the script withoutsource` 的脚本中添加一个 shebang:

    #!/bin/echo source this script from csh: source
    

    ...这是一种 hack,因为 /bin/echo 不是解释器;但它会运行命令/bin/echo source this script from csh: source /path/to/script,这至少将用户指向正确的方向。请注意,这并不能防止有人用shbash 等覆盖shebang。

顺便说一句,关于不兼容命令的其他几点说明:正如我所说,set 在类 sh 和类 csh 的 shell 中做完全不同的事情。在类似 csh 的 shell 中,您使用 set var=value 分配变量,但在类似 sh 的 shell 中,set 设置脚本的位置参数($1$2 等),所以 set var=value$1 设置为字符串“变量=值”。另外,在您的回答中,您使用了dir 命令——这根本不是unix 命令,而是DOS 命令;这表明您在 Windows 下运行这些脚本,在这种情况下,潜伏着另一类潜在的兼容性混乱。

【讨论】:

  • 感谢您的详尽解释。一个问题,如果我按照我在问题中所说的那样运行 chmod +x testtest 会怎样?我认为它不会生成外壳。这是正确的吗? (我在做某事,但会测试它)。我用ls而不是dir(我的错误,我有多不正确......我会修复它。)
  • 如果你只是使用脚本名称(或路径)来运行它,它正在创建一个子进程。根据脚本是否有 shebang,你会得到我描述的第一个或第二个场景。
【解决方案3】:

您应该将 shebang 添加到您的脚本中以强制使用 tcsh 否则将使用默认外壳!!! 并且您的变量定义/赋值语法可能无法按预期工作!

将以下第一行添加到您的脚本中

#!/usr/bin/env tcsh

【讨论】:

  • 我想不使用 #!/usr/bin/env tcsh 或 #!/bin/csch 或 #!/bin/tcsh。这是不可能的吗? (我不想启动一个新的 shell,但使用相同的别名和其他以前的环境变量等)
  • @ChanKim 当你正常运行一个脚本时,它总是在一个新的shell中运行。如果你有一个 shebang,它会告诉操作系统使用哪个 shell;如果没有shebang,它会有点不可预测,但可能是sh-like,而不是csh-like。这很重要,因为类 sh 的 shell 的语法与类 csh 的 shell 非常不同。就您的脚本而言,问题在于set 在类似 sh 的 shell 与类似 csh 的 shell 中意味着完全不同的东西。基本上,如果您想保持理智,请使用适当的 shebang。
  • @GordonDavisson 那么,如果我想使用我在shell中设置的变量,我应该如何启动脚本呢?如果我使用shebang,我设置的那些环境将不会被看到。
  • @ChanKim 查看我的回答(和 ghoti 的评论)。
猜你喜欢
  • 1970-01-01
  • 2019-11-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-26
  • 2017-06-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多