Bash如何在不同的目录上下文中执行命令?

162

我有一个常用命令,需要从特定的目录中调用。该程序只有一个可执行文件位于/bin中,当前工作目录对于正确运行它非常重要。该脚本会影响在其所在目录中的文件。

现在,我还有一个自定义的shell脚本,在一个目录中进行一些操作,但我需要调用上述命令,就像它在另一个目录中一样。

如何在shell脚本中实现这个功能?


7个回答

339

在子shell中使用cd命令;使用这种类型的子shell的简写方式是使用圆括号。

(cd wherever; mycommand ...)

话虽如此,如果您的命令需要特定的环境,则应确保该环境而不是将责任放在可能想要使用它的任何东西上(除非它是在完全定义良好的更大系统的特定情况下使用的内部命令,以便任何调用者已经需要确保其所需的环境)。通常这将是某种shell脚本包装器。


2
您还可以在同一上下文中的多行命令后面插入“\”以实现多行命令。 - Chiramisu
这就是方法。 - Adam Erickson
只要生成新的shell不是问题,这个解决方案就很好。 - undefined

52
(cd /path/to/your/special/place;/bin/your-special-command ARGS)

45

你可以使用内置命令 cdpushdpopd 来实现这个目的。例如:

# do something with /etc as the working directory
cd /etc
:

# do something with /tmp as the working directory
cd /tmp
:

您可以像使用任何其他命令一样使用内置命令,并且在脚本中可以随意更改目录上下文。


6
在 POSIX shell 中也有 cd - 可以返回上一个目录。尽管如此,(a) pushdpopd 确实是为交互式使用而设计的,(b) 在复杂的子系统中,不能总是安全地假设您可以返回原来的目录,特别是当它们可能在内部使用限制权限时(请参见 https://dev59.com/GGPVa4cB1Zd3GeqP8b2p)。 - geekosaur
4
使用子Shell是一个更好的解决方案。 - josh123a123
对于脚本编写,子shell 可能是一个更好的选择。不过我真的很高兴学到了 popd - connorbode
1
请问这里的 : 符号是什么意思? - Vadim Kotov
2
@VadimKotov 我认为这实际上是一个无操作。在 man bash 的相关部分中,写着:: [arguments] 无效果; 命令除了扩展参数和执行任何指定的重定向外,什么也不做。返回状态为零。 - boycy
对于任何感兴趣的人,请查看此处 - https://dev59.com/unA75IYBdhLWcg3wkZ6A - Vadim Kotov

30

如果您想返回当前工作目录:

current_dir=$PWD;cd /path/to/your/command/dir;special command ARGS;cd $current_dir;
  1. 我们将一个变量current_dir设置为你的pwd
  2. 然后我们将要cd到你需要运行命令的位置
  3. 接着我们运行命令
  4. 最后我们将要cd回到我们的current_dir变量中
pushd && cd /path/to/your/command/dir && special command ARGS && popd

感谢 @apieceofbart 和 @Konstantin 的支持


6
或者你可以使用 pushd && YOUR COMMAND && pulld 这个命令。 - apieceofbart
8
我认为你的意思是“popd”而不是“pulld”。 - Konstantin
4
我相信最后的命令应该是: pushd /path/to/your/command/dir && 特殊命令参数 && popd - M.Adam
1
如果您的特殊命令失败,这些解决方案可能会产生奇怪的结果。使用分号的解决方案不会传播命令返回值,但会保留当前工作目录。而使用"&&"的解决方案会让您停留在错误的目录中。 - undefined

2

您也可以使用env命令来实现相同的功能,而无需额外的shell:

env --chdir=/whatever/path -S whatever_command -some -option and any other arguments

其中whatever_command是要执行的命令或脚本以及所有相关选项和参数。所有这些必须遵循env命令的-S选项。

当前工作目录只在execvp()系统调用中更改,因此最终它将返回到其原始值。

envGNU coreutils软件包的一部分,可以在这里找到其手册页面以获取更多详细信息。

实际上,您还可以使用env来仅针对特定执行操作环境变量和信号处理。


1

警告!!!

迟到回答这个问题,我必须指出:这里没有回答到ShellCheck SC2164!!

解释:如果在执行破坏性命令之前遇到拼写错误的路径:

( cd /wrong/path ; rm -fR * )

cd命令会失败,然后后续命令会摧毁当前目录中的所有内容!!

因此,正确的命令是

( cd /path/to/wherever || exit; mycommand ... )

或者

( cd /path/to/wherever && mycommand ... )

0

简单实用的小技巧:

这将把shell目录更改为~/project

function mymake() {
    cd ~/project && make $1
}

这不会

function mymake() {
    (cd ~/project && make $1)
}

运行

mymake something

1
因此,基本上使用花括号而不是括号来包装函数内容。 - god_is_love
不行。这基本上是糟糕的bash编程。他们在没有块的情况下定义了一个函数,使用单个括号作为表达式。括号创建一个新的shell,该shell将退出并恢复旧的shell。如果此人想要避免未来的bash程序员在调试会话中感到沮丧,他们应该这样做:function mymake() { ( cd ~/project && make $1 ) },以避免括号被误认为是花括号的简单错误。 - Edwin Buck

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接