システムメッセージ

システムメッセージ

システムメッセージ

オペレーティングシステム:OS X

bash: GNU bash, バージョン 3.2.57(1)-リリース(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

ベストアンサー1

強制を使用して別の評価を実行することもできますが、eval実際にはそうする必要はありません。 (evalファイル名になどの特殊文字が含まれると深刻な問題が発生し始めます$。)問題はワイルドカードではなくチルダ拡張です。

ワイルドカード発生後ろに変数拡張、変数が引用されていない場合は次のようになります(*)

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

引用符のない拡張で発生するもう1つのことはトークン化です。IFSこれは、問題のパターンに文字(通常はスペース)が含まれている場合に問題になります。この問題を回避するには、IFS単語の区切りを空の文字列に設定して無効にする必要があります。

もう一度申し上げますが、これはあなたがしたことに似ており、うまくいきます。

$ IFS=
$ 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

これは明確に文書化大きな打撃の場合:

拡張順序は、中かっこ拡張、パラメータおよび変数拡張、...です。

チルダ拡張は変数拡張の前に行われるため、変数内のチルダは拡張されません。簡単な修正方法は、代わりにまたは$HOMEフルパスを使用することです。

(*変数からglobを拡張することは通常望むものではありません)


もう一つのこと:

次のようにパターンを繰り返します。

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

$exclude引用されていないので分割され、ワイルドカードとして表示されます。したがって、現在のディレクトリにこのパターンに一致するエントリが含まれている場合は、次のように展開されます。

$ IFS=
$ i="$HOME/public/foo"
$ exclude="*.launch"
$ touch $i/real.launch
$ for j in $exclude ; do           # glob, no match
    printf "%s\n" "$i"/$j ; done
/home/foo/public/foo/real.launch

$ touch ./hello.launch
$ for j in $exclude ; do           # glob, matches in current dir!
    printf "%s\n" "$i"/$j ; done
/home/foo/public/foo/hello.launch  # not the expected result

この問題を解決するには、次を使用します。配列変数文字列を分割する代わりに:

$ IFS=
$ exclude=("*.launch")
$ exclude+=("*.not this")
$ for j in "${exclude[@]}" ; do printf "%s\n" "$i"/$j ; done
/home/foo/public/foo/real.launch
/home/foo/public/foo/some file.not this

ただし、パターンが何も一致しない場合、デフォルトではそのまま残ります。したがって、ディレクトリが空の場合は.../*.launch印刷されます。


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代わりに使用し、コマンドラインから引用符をオフにして分割する必要がありますが、誤ってシェルから拡張されないように引用する必要があります。~$dirsfind$pattern

-maxdepth(興味があればGNU findを使用して検索の深さを制限できると思いますが、それは別の質問です。)

おすすめ記事