将目录更改为名称为正则表达式

时间:2018-01-04 17:09:56

标签: regex bash

我在包含许多文件夹的目录中:

At_5.2000_displacement
At_-6.4000_displacement
At_2nd_-4.3000_displacement
At_2nd_2.2000_displacement

我正在编写一个bash脚本cd - 每个类型的文件夹:

At_X.XXXX_displacement

即,我想

cd At_5.2000_displacementcd At_-6.4000_displacement个文件夹。这省略了类型的文件夹:

At_2nd_X.XXXX_displacement

我的尝试(已编辑):

我找到了产生目标文件夹名称的reg-ex,如下所示:

At_-\?[0-9][.].*displacement

产生:

At_5.2000_displacement
At_-6.4000_displacement

现在,在bash脚本中,每次我都这样做:

cd /path_to_the_folders/At_-\?[0-9][.].*displacement

无法访问每个文件夹,因为收到的错误是:

trial_cding.sh: line 11: cd: /path_to_the_folders/At_-?[0-9][.].*displacement: No such file or directory

如何让行cd /path_to_the_folders/At_-\?[0-9][.].*displacement生效?

根据我的理解,@ dawg通过if语句(不使用快捷方式)的答案实现如下:

for pn in *; do

    if [[ ! -d "$pn" && $pn =~ At_[0-9.-]*_displacement ]]
    then
        echo No desired directory found 
    else
         continue

    cd $pn
    pwd
    cd -
    fi
done

但是,这不会返回任何结果。我在这里弄错了什么?

此外,我不太确定如何在cd $pn中使用括号以避免返回

关于[0-9.-]匹配......

最后我们正在寻找正或负十进制数。 换句话说,我们正在寻找从( - )0到( - )9的任何数字,然后是.

这让我觉得[-0-9.]是最直观的指示。

令人惊讶的是,碰巧以下三个也匹配:

[0-9.-]
[0-9-.]   
[-.0-9]

请查看我显示比赛的https://regex101.com/r/G3fXo5/1。这让我觉得[ ]内的匹配条件非常广泛。

所以,我试试[.-0-9]我得不到匹配的结果。为什么会这样?内部匹配[ ]背后的规则是什么?

3 个答案:

答案 0 :(得分:3)

假设X只能是一个数字,你可以使用扩展的globbing:

shopt -s extglob nullglob
for folder in At_?(-)[0-9].[0-9][0-9][0-9][0-9]_displacement/; do
    #do stuff here
    echo "$folder"
done
  • shopt -s nullglob是为了确保在没有与您的模式匹配的文件时不会循环
  • shopt -s extglob启用扩展的全局
  • ?(-)匹配-零次或一次匹配。在扩展的全局中,修饰符出现在(pattern)之前。请参阅:Pattern matching

此方法的优点是仅在您真正想要的文件夹上循环。无需额外检查。

答案 1 :(得分:1)

假设:

$ ls -l
total 0
drwxr-xr-x  2 dawg  wheel  68 Jan  4 10:42 At_-6.4000_displacement
drwxr-xr-x  2 dawg  wheel  68 Jan  4 10:42 At_2nd_-4.3000_displacement
drwxr-xr-x  2 dawg  wheel  68 Jan  4 10:42 At_2nd_2.2000_displacement
drwxr-xr-x  2 dawg  wheel  68 Jan  4 10:42 At_5.2000_displacement
-rw-r--r--  1 dawg  wheel   0 Jan  4 10:51 file

你可以使用常规的Bash glob *,测试看每个glob是一个目录-d(与其他一些OS对象相比),然后使用Bash正则表达式测试字符串:

for pn in *; do   # You could use At_*_displacement glob to narrow if desired...
    [[ -d "$pn" && $pn =~ At_[0-9.-]*_displacement ]]  || continue
       # ^^                           a directory?
       #        ^^                    and
       #                ^     ^^      match this regex
       #        OR                                     ^   
       # continue (skip) to the next glob pattern in loop     ^^
    # do you Bash thing on this directory...
    # you can cd "$pn" or operate on the directory directly
    # ( use parenthesis for a sub shell and you don't need to cd back )
    echo "$pn"
done    

打印:

At_-6.4000_displacement
At_5.2000_displacement

您还可以将find与适当的深度限定符和正则表达式一起使用:

$ find . -type d -maxdepth 1 -regex '\./At_[0-9.-]*_displacement'
./At_-6.4000_displacement
./At_5.2000_displacement

然后使用exec {}xargs或将该输出反馈给Bash while循环。

上次编辑,如下所示:

for pn in *; do
    if [[ -d "$pn" && $pn =~ At_[0-9.-]*_displacement ]]
    then
        ( # the ( creates a subshell so no need to cd back...
        echo "Found \"$pn\"! Touching it!"
        cd "$pn"   # USE QUOTES!
        # you are now in that sub directory
        touch "dawg was here!"   # create a file in the directory...
        )
        # exit sub shell -- back to the original directory
    else
         echo "\"$pn\" is not what we are looking for..."
    fi
done

请务必在Bash扩展中使用“$ quotes”。

答案 2 :(得分:0)

cd一次不能更改为多个目录。你需要一个for循环。

这个怎么样:

for i in `ls | grep "^At_-\?[0-9][.].*displacement$"`; do
    cd $i
    # do what needs to be done
done