【问题标题】:bash script to create and cd to directory with spaces in name [duplicate]bash脚本创建并cd到名称中带有空格的目录[重复]
【发布时间】:2016-07-22 17:12:59
【问题描述】:

我正在开发一个项目,以在我的 GitLab CE 实例中远程创建一个存储库(该部分正在运行!),然后使用项目名称创建一个目录(正在运行!)并 cd 进入该目录(这里是我有问题的地方...),然后在本地初始化并添加远程存储库(工作!!!)

我遇到的问题只是更改为新目录。无论我使用下面显示的代码,还是简单地尝试cd "$1"cd "$*",我似乎都无法让它工作!

#!/bin/bash

dir="$*"
wd=$(pwd)
fulldir="$(pwd)/${dir// /\\ }/"
echo "Creating directory $dir"
mkdir -v "$dir"
cd "$dir"
echo "Changing current directory to $dir"
echo $dir
echo $fulldir

这段代码的输出是:

root@cana:~# ls
glnewproj  test
root@cana:~# bash test Hello World
Creating directory Hello World
mkdir: created directory 'Hello World'
Changing current directory to Hello World
Hello World
/root/Hello\ World/
root@cana:~# ls
Hello World  glnewproj  test
root@cana:~# pwd
/root

如何cd 进入我新创建的目录?我完全被难住了。

编辑:

按 ghoti 键入函数并在 .bashrc 和我的测试脚本中对其进行测试。

直接从 bash 运行函数时:

root@cana:~# ls
glnewproj  test  test2
root@cana:~# mkcd "Hello World"
root@cana:~/Hello World# 

在新的测试脚本中运行函数时:

root@cana:~# ls
glnewproj  test  test2
root@cana:~# cat test2
#!/bin/bash

mkcd() {
  mkdir -p "$1" && cd "$1"
}

mkcd "$1"

root@cana:~# bash test2 "Hello World"
root@cana:~# ls
Hello World  glnewproj  test  test2

所以脚本仍然作为子脚本运行,因此不会更新父 shell 的当前目录。在脚本末尾生成一个新的 shell 是我唯一的选择吗?

【问题讨论】:

  • 您的test2 脚本仍然是一个单独的脚本,并且不在您的交互式shell 中运行。 test2 内部有自己的函数mkcd 的事实并没有改变它在您通过在交互式shell 中运行bash 创建的子shell 中运行的事实。不要运行 `bash test2 "Hello World",而是在运行的 shell 中将 test2 设为一个函数,然后运行该函数。
  • 然而,我想要做的完全取决于它是一个脚本。
  • 嗯,您现在有多个答案,包括您自己的答案,并且您明白为什么会遇到问题。如果您真的希望能够将交互式 shell 中的目录更改为由脚本创建的目录,那么有多种方法可以将它们组合在一起,我在回答中已经描述了一种。鉴于您问题的详细程度,我不可能知道它是否适用于您。
  • 如果可以,我很懒惰,我在我的 bash 别名中有这个(→这里,cd 将在“脚本”结尾之后仍然有效):function mkcd(){/usr/bin/mkdir -p "$*"@ 987654335@}。因此,我可以在所有懒惰和没有 any 引号的情况下说:mkcd network testing

标签: linux bash unix mkdir cd


【解决方案1】:

您的脚本(大部分)没问题,只要您使用问题中提到的cd "$1"。问题是您需要确保完整的目录名称实际上是作为单个参数传递的。

$ bash test "Hello World"

然后在你的脚本中

# Omitting unused $wd
# Omitting $fulldir, which appeared to be for debugging purposes only
dir=$1
mkdir -v "$dir"
cd "$dir"

【讨论】:

  • 不幸的是,这也不会改变我的目录。
【解决方案2】:

经过更多研究,我发现这是因为脚本是子进程,无法影响父 shell。也就是说,脚本会为自己的目的而cd。例如,我可以将代码更改为以下内容:

#!/bin/bash

dir=$1
mkdir -v "$dir"
cd "$dir"
touch test.file

然后运行

$ bash test "Hello World"

结果将是文件test.file 出现在./Hello\ World/ 中,但是当脚本完成时,我仍然会在之前的工作目录中。

获得我想要的结果的一种草率方法是将cd 放入新目录,即使用exec bash 在脚本中生成一个新会话。

【讨论】:

    【解决方案3】:

    当您从脚本中cd 时,您的目录会在脚本中更改,但不会在调用shell 中更改。交互式 shell 中的工作目录是由那个 shell 中的cd 命令设置的,而不是在它运行的程序中。

    如果您希望您的脚本能够更改交互式 shell 的目录,那么您可能需要设置一个 bash 函数。例如,可以将以下内容添加到您的.bash_profile

    mkcd() {
      mkdir -p "$1" && cd "$1"
    }
    

    由于此函数在交互式 shell 的上下文中运行,而不是生成子 shell 或子进程,因此它所做的目录更改在退出后会保留。


    如果您需要/想要使您的目录创建脚本成为一个独立的工具,另一种选择是在 mktemp 之后建模事物,这会创建它需要的东西,然后将它创建的东西的名称返回到标准输出。因此,使用以下脚本,可能称为mkcd

    #!/bin/bash
    
    if mkdir -p "$*"; then
      cd -P "$*"
      pwd
      r=0
    else
      r=$?
    fi
    
    exit $r
    

    然后在你的调用脚本中,你可以这样运行:

    #!/bin/bash
    
    d=$(mkcd Hello World)
    
    if [ ! -d "$d" ]; then
      echo "ERROR: I can't go on like this" >&2
      exit 1
    fi
    
    cd "$d"
    : do your stuff
    

    请注意,即使看起来多余,错误检查仍然是一个好主意,因为如果使用特殊字符或奇怪的格式来构建目录名称,人们可能会成为意外或故意不可预测的行为的受害者。

    【讨论】:

    • 所以这个应该放在.bashrc 是吗?然后从脚本运行时,它应该在脚本之外运行,并且我可以避免根据我的答案产生惊人数量的会话。 :P
    • 在您的.bashrc 中可以使用,或者在您的.bash_profile 中使用,如果这是用于交互使用的话。例如,要在您从 cron 运行的脚本中使用,您只需将其添加到脚本的顶部即可。我不确定您的用例,我们可能会将其设为XY problem...
    • 我遇到了一些奇怪的行为。我已将其添加到.bashrc,如果我直接从 shell 运行该函数,则会获得所需的结果,但如果我将其作为脚本运行,则脚本仍在执行它并且不会影响父 shell。
    • 如何在脚本中调用它?也许你可以用这些实验和你的结果来更新你的问题。
    • 用更多信息更新了问题。
    猜你喜欢
    • 2010-10-10
    • 2013-08-21
    • 1970-01-01
    • 1970-01-01
    • 2016-02-27
    • 1970-01-01
    • 2015-06-03
    • 2021-05-09
    • 2013-12-02
    相关资源
    最近更新 更多