cd到bash脚本中以波浪号(〜)开头的文件夹名称 [英] cd to a folder name starting with tilde (~) in bash script

查看:34
本文介绍了cd到bash脚本中以波浪号(〜)开头的文件夹名称的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试创建一个执行以下操作的非常简单的bash脚本:

I'm trying to create a very simple bash script that does the following:

  • 输入用户进入项目文件夹
  • 设置在变量中输入的值
  • cd到输入的文件夹
  • 删除readme.md文件

根据我所读到的内容,我提出了以下建议:

From what I've read around I've come up with this:

#!/bin/bash

echo "Enter the project folder path:"
read -e DESTINATION_FOLDER

cd "$DESTINATION_FOLDER"
rm -rf "$DESTINATION_FOLDER/readme.md"

我输入的文件夹路径为

〜/Dropbox/myproject

~/Dropbox/myproject

我得到的错误是下面的错误.但是,该文件夹存在,我可以使用cd命令手动访问它.

And the error I get is the one below. However that folder exists and I can access it manually using the cd command.

./cleanup.sh: line 6: cd: ~/Dropbox/myproject/: No such file or directory

有人可以指出我在做什么错吗?

Can anyone please point out what I'm doing wrong?

推荐答案

波浪号()仅在直接出现(且不加引号)的情况下才扩展到主目录.当您使用 cd"$ DESTINATION_FOLDER" 时,将直接使用 $ DESTINATION_FOLDER 中的字符,包括前导.即使您使用了 cd $ DESTINATION_FOLDER ,也将直接插入,尽管 $ DESTINATION_FOLDER 中的空格和glob元字符也将被扩展.因此,实际上没有办法对变量中的值进行波浪号扩展.[注1]

The tilde (~) is only expanded to the home directory if it appears directly (and is not quoted). When you use cd "$DESTINATION_FOLDER", the characters in $DESTINATION_FOLDER are used literally, including the leading ~. Even if you had used cd $DESTINATION_FOLDER, the ~ would have been inserted directly, although whitespace and glob metacharacters in $DESTINATION_FOLDER would have been expanded. So there is really no way to do tilde expansion on a value in a variable. [Note 1]

有些人会建议使用 eval ,但是您必须对此非常小心.如果 $ DESTINATION_FOLDER 包含外壳程序元字符,则 eval cd"$ DESTINATION_FOLDER" 可能会出现意外结果.例如,考虑以下内容(不要在包含您关心的文件的目录中尝试此操作)

Some people will suggest using eval, but you have to be very careful about that. eval cd "$DESTINATION_FOLDER" could have unexpected results if $DESTINATION_FOLDER includes a shell metacharacter. Consider the following, for example (don't try this in a directory which contains files you care about):

$ mkdir -p ~/tmp/foo && cd ~/tmp/foo
$ touch a few files
$ ls
a  few  files
$ x="~/tmp/foo;rm *"
$ # BEWARE!
$ eval cd "$x"
$ # OOPS!
$ ls
$

正确的方法是自己扩展波浪号:

The correct way to do this is to expand the tilde yourself:

cd "${DESTINATION_FOLDER/#~/$HOME}"

bash 中, $ {var/pattern/replacement} 根据 $ var 的值生成一个字符串,其中第一个实例 pattern (如果有的话)被替换为 replacement .仅当 pattern 出现在 $ var 的开头时,格式 $ {name/#pattern/replacement} 才进行替换. pattern 是一个glob,而不是正则表达式.

In bash, ${var/pattern/replacement} produces a string based on the value of $var, where the first instance of pattern (if any) is replaced with replacement. The form ${name/#pattern/replacement} only does the replacement if pattern occurs at the beginning of $var. pattern is a glob, not a regular expression.

在一条评论中,汤姆·费内奇建议,如果可以处理〜user 以及.同样,处理诸如〜+ 2 [注2]之类的bashism甚至会更酷.

In a comment, Tom Fenech suggested that it would be cool if it were possible to handle ~user as well as just ~. In the same vein, it would be even cooler to handle bashisms like ~+2 [Note 2].

的确.不幸的是, bash 没有提供可进行波浪号扩展的内置函数.或其他任何形式的扩展.因此,我认为有必要使用 eval ,但是如上所述,这需要非常谨慎.我认为最好的办法是仅在不包含元字符的情况下提取代字号前缀,然后再使用 eval printf%s 对其进行扩展,如下所示:

Indeed. Unfortunately, bash does not provide a builtin which does tilde expansion. Or any other kind of expansion. So I think it is necessary to use eval, but that requires considerable caution, as mentioned above. I think that the best that can be done is to extract the tilde-prefix only if it contains no metacharacters, and only then expand it with eval printf %s, something like this:

tilde-expand() {
  (
    shopt -s extglob
    if [[ $1 =~ ^~[[:alnum:]_.+-]*(/.*)?$ ]]; then
      printf %s "$(eval printf ${1%%/*})${1##*([^/])}"
    else
      printf %s "$1"
    fi
  )
}

(以上内容尚未经过仔细测试.与往常一样, eval 应该谨慎对待,因此请在部署之前仔细检查.)

(The above hasn't been carefully tested. As always, eval should be treated with the greatest of caution, so please examine carefully before deploying.)

注释:

  1. 通常,这无关紧要,因为大多数脚本都将输入作为参数,而不是从控制台读取它们.这样的脚本可能编写如下:

  1. In general, this doesn't matter, because most scripts take input as arguments rather than reading them from the console. Such a script might be written as follows:

cdrm() {
  cd "$1" && rm -rf readme.md
}

然后您就可以使用波浪号来调用它:

then you would be able to invoke it using a tilde:

cdrm ~/Dropbox/myproject/

因为将在对 cdrm 的调用中扩展,所以 $ 1 将具有扩展值.

because the ~ will be expanded in the call to cdrm, so that $1 will have the expanded value.

我从没使用过〜+ N 波浪线扩展名,但是可能有些人发现它们 essential .

I've never used ~+N tilde expansions, but there are probably people who find them essential.

这篇关于cd到bash脚本中以波浪号(〜)开头的文件夹名称的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆