加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

如何使bash glob成为字符串变量?

发布时间:2020-12-16 01:44:33 所属栏目:安全 来源:网络整理
导读:系统信息 操作系统:OS X. bash:GNU bash,版本3.2.57(1)-release(x86_64-apple-darwin16) 背景 我希望时间机器从我的所有git / nodejs项目中排除一组目录和文件.我的项目目录在?/ code / private /和?/ code / public /所以我试图使用bash循环来执行tmutil.
系统信息

操作系统:OS X.

bash:GNU bash,版本3.2.57(1)-release(x86_64-apple-darwin16)

背景

我希望时间机器从我的所有git / nodejs项目中排除一组目录和文件.我的项目目录在?/ code / private /和?/ code / public /所以我试图使用bash循环来执行tmutil.

问题

精简版

如果我有一个计算的字符串变量k,如何在for循环之前或之前使其成为全局变量:

i='~/code/public/*'
j='*.launch'
k=$i/$j # $k='~/code/public/*/*.launch'

for i in $k # I need $k to glob here
do
    echo $i
done

在下面的长版本中,您将看到k = $i / $j.所以我不能在for循环中对字符串进行硬编码.

长版

#!/bin/bash
exclude='
*.launch
.classpath
.sass-cache
Thumbs.db
bower_components
build
connect.lock
coverage
dist
e2e/*.js
e2e/*.map
libpeerconnection.log
node_modules
npm-debug.log
testem.log
tmp
typings
'

dirs='
~/code/private/*
~/code/public/*
'

for i in $dirs
do
    for j in $exclude
    do
        k=$i/$j # It is correct up to this line

        for l in $k # I need it glob here
        do
            echo $l
        #   Command I want to execute
        #   tmutil addexclusion $l
        done
    done
done

产量

它们不是全球化的.不是我想要的.

~/code/private/*/*.launch                                                                                   
~/code/private/*/.DS_Store                                                                                  
~/code/private/*/.classpath                                                                                 
~/code/private/*/.sass-cache                                                                                
~/code/private/*/.settings                                                                                  
~/code/private/*/Thumbs.db                                                                                  
~/code/private/*/bower_components                                                                           
~/code/private/*/build                                                                                      
~/code/private/*/connect.lock                                                                               
~/code/private/*/coverage                                                                                   
~/code/private/*/dist                                                                                       
~/code/private/*/e2e/*.js                                                                                   
~/code/private/*/e2e/*.map                                                                                  
~/code/private/*/libpeerconnection.log                                                                      
~/code/private/*/node_modules                                                                               
~/code/private/*/npm-debug.log                                                                              
~/code/private/*/testem.log                                                                                 
~/code/private/*/tmp                                                                                        
~/code/private/*/typings                                                                                    
~/code/public/*/*.launch                                                                                    
~/code/public/*/.DS_Store                                                                                   
~/code/public/*/.classpath                                                                                  
~/code/public/*/.sass-cache                                                                                 
~/code/public/*/.settings                                                                                   
~/code/public/*/Thumbs.db                                                                                   
~/code/public/*/bower_components                                                                            
~/code/public/*/build                                                                                       
~/code/public/*/connect.lock                                                                                
~/code/public/*/coverage                                                                                    
~/code/public/*/dist                                                                                        
~/code/public/*/e2e/*.js                                                                                    
~/code/public/*/e2e/*.map                                                                                   
~/code/public/*/libpeerconnection.log                                                                       
~/code/public/*/node_modules                                                                                
~/code/public/*/npm-debug.log                                                                               
~/code/public/*/testem.log                                                                                  
~/code/public/*/tmp                                                                                         
~/code/public/*/typings

解决方法

您可以使用eval强制进行另一轮评估,但这实际上并不是必需的. (当你的文件名包含像$这样的特殊字符时,eval开始出现严重问题.)问题不在于globbing,而在于tilde扩展.

如果变量未加引号,变量扩展后会发生Globbing,就像这里(*):

$x="/tm*" ; echo $x
/tmp

所以,同样的,这与你所做的类似,并且有效:

$mkdir -p ~/public/foo/ ; touch ~/public/foo/x.launch
$i="$HOME/public/*"; j="*.launch"; k="$i/$j"
$echo $k
/home/foo/public/foo/x.launch

但是对于波浪号,它不会:

$i="~/public/*"; j="*.launch"; k="$i/$j"
$echo $k
~/public/*/*.launch

对于Bash来说这是clearly documented:

The order of expansions is: brace expansion; tilde expansion,parameter and variable expansion,…

Tilde扩展在变量扩展之前发生,因此变量内部的变量不会扩展.简单的解决方法是
使用$HOME或完整路径.

(*从变量扩展globs通常不是你想要的)

另一件事:

循环遍历模式时,如下所示:

exclude="foo *bar"
for j in $exclude ; do
    ...

请注意,因为$exclude是不加引号的,所以它们都是拆分的,并且在这一点上也是全局的.因此,如果当前目录包含与模式匹配的内容,则会扩展为:

$i="$HOME/public/foo"
$exclude="*.launch"
$touch $i/real.launch
$for j in $exclude ; do           # split and glob,no match
    echo "$i"/$j ; done
/home/foo/public/foo/real.launch

$touch ./hello.launch
$for j in $exclude ; do           # split and glob,matches in current dir!
    echo "$i"/$j ; done
/home/foo/public/foo/hello.launch  # not the expected result

要解决此问题,请使用array variable而不是拆分字符串:

$exclude=("*.launch")
$exclude+=("something else")
$for j in "${exclude[@]}" ; do echo "$i"/$j ; done
/home/foo/public/foo/real.launch
/home/foo/public/foo/something else

作为一个额外的好处,数组条目也可以包含空格而不会出现拆分问题.

如果你不介意目标文件应该是什么目录级别,可以使用find -path做类似的事情.例如.找到以/e2e/*.js结尾的任何路径:

$dirs="$HOME/public $HOME/private"
$pattern="*/e2e/*.js"
$find $dirs -path "$pattern"
/home/foo/public/one/two/three/e2e/asdf.js

出于与以前相同的原因,我们必须使用$HOME而不是?,并且$dirs需要在find命令行上不加引号,因此它会被拆分,但是$pattern应该被引用,因此它不会被shell意外扩展.

(我认为你可以在GNU上使用-maxdepth来限制搜索的深度,如果你关心,但这是一个不同的问题.)

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读