mkdir、touchなどのbash / shellパス名拡張?

mkdir、touchなどのbash / shellパス名拡張?

したがって、他のほとんどのシェルで同様の操作を実行すると、bashサブディレクトリ内に複数のサブディレクトリやファイルが作成されません。

mkdir */test
touch */hello.txt

もちろん、これを実際に行う方法はいくつかあります。私が好む方法は、主に可読性のために可能な限りループのfind代わりに使用することです。for

しかし、私の質問は、上記の方法がなぜ機能しないのですか?
私が理解したのは、ターゲットファイル/パス全体が存在しないためです。しかし、試してみるとmkdir確かに良いですtouch。私はいつも前進し、それについて本当に疑問を抱いていませんでした。
しかし、私が完全に理解できるように、これについて適切な説明を提供する人はいますか?

答え1

特に *nix を使用する前に他のオペレーティングシステムを使ってみた経験がある場合、多くの人が問題を抱えているという事実を見落とすことができるのは、他の多くのオペレーティングシステムではコマンドラインにワイルドカードを渡すのが一般的なことです。 。 命じる適切と判断されるとおりに処分してください。たとえば、Windowsのコマンドプロンプトで次のようになります。

rename *.jpeg *.jpg

ただし、* nixでは、  mvプログラマーの個々のコマンド(例:)の操作を簡素化するために、ワイルドカード(引用符で囲んだりエスケープしていない場合)はインターフェースに依存しない方法でシェルで処理されます。ワイルドカードはコマンド機能の引数として使用されます。ファイル名をコマンドライン引数として使用するほとんどのプログラムは、これらのファイルが存在すると予想しています(たとえば、、、およびある程度、、、およびなどの規則の例外であり、mkdir他のファイルもあります)。シェルがワイルドカードを存在しないファイル名に拡張することは実際には意味がありません。殻の場合(私の言葉はtouchmkfifomknodcplnmvrenameすべてシェル – Bourne、bash、csh、fish、ksh、zshなど)は、さまざまな方法で例外を処理するのが難しい場合があります。


つまり、所望の結果を得る方法はいくつかある。ワイルドカードがどのように拡張されるのかを知っていて、長さが長くない場合は、中かっこ拡張を使用して生成できます。

touch {red,orange,yellow,green,blue,indigo,violet}/rgb.txt

より一般的な解決策:

sh -c 'for arg do mkdir -- "$arg"/test; done' -- *

ザイルズBashでこれを行う他の方法を見つけるのに役立ちました。

benbradley=(*)
mkdir "${benbradley[@]/%//test}"

明らかに、benbradleyこれは単なる識別子です。任意の名前(たとえば、単一文字)を使用できます。きちんと理解するために何度も試してみたので分析してみましょう。

  • identifier=valueidentifier (まだ存在しない場合)という名前の(スカラー)変数を作成し、value値を割り当てます。たとえば、G=Man。例えば;または、より安全にを使用してスカラー変数を参照できます。たとえば、andは定義されていませんが、is and isです。$identifier$G${identifier}$Gage$Gilla${G}ageManage${G}illaManilla
  • identifier=(value1 value2)identifier (まだ存在しない場合)という配列変数を作成し、リストされた値を割り当てます。例えば、
      スペクトル=(赤、オレンジ、黄色、緑、青、藍、紫)
    または
      all_text_files=(*.txt)
    $name最初の要素を参照しているので、むしろ役に立ちません。たとえば、isやisなど、すべての要素を参照できます。とを使用して配列全体を参照できます。${name[subscript]}${spectrum[0]}red${spectrum[4]}blue${name[@]}${name[*]}

だから、ここに彫刻があります:

      "${ベンブラドリー[@]/%//テスト}"
  • ${parameter/pattern/string} 延長および交換された最も長い一致。${parameter}patternstring
  • patternで始まる場合は、#拡張値の先頭で一致する必要がありますparameterpatternで始まる場合は、%拡張値の最後に一致する必要がありますparameter。つまり、
      %(残りのパターン)
    のように振る舞う
      (残りの正規表現)$
    (はい、少し逆さまになったようです)。したがって、aは正規表現と同じです。pattern入力文字列(検索スペース)の終わりと一致します。%$
  • stringは使用しています/test。したがって、これはパラメータの終わりを次に置き換えます(つまり、パラメータに/test 追加されます)。/test
  • 直感的ではないもう一つの点は${parameter/pattern/string}いつも}次に終わります。必須ではなく、できない、3番目に終わります/。したがって/string区切り記号として解釈できないのでstring/test 脱出する必要なしに/
  • または で索引付けされた配列変数の場合、parameter置換操作は配列の各メンバーに順番に適用されます。@*
  • 配列を(代わりに)引用し、結果を二重引用符で囲むと、個々の要素を1つの長い単語にまとめることなく、配列要素の整合性(スペースやその他の特殊文字の保持など)が維持されます。${name[@]}${name[*]}

答え2

シェルは、コマンドを呼び出す前にワイルドカードパターンを拡張します。バラよりGマンの答え完全な説明のために。

ほとんどのシェルには、一致にテキスト変換を適用するための一種の中間コマンドが必要です。 Zshはすぐに一致を変更する方法を提供します。グローバル予選:

  • eまたは、文字列(または配列を変更して一致数)を変更して変更できる+各一致に対してコードを実行します。REPLYreply
  • :それから歴史拡張修飾子一部の組み込み変換の適用

例:

mkdir */(:s:/:/test:)     # takes advantage of the fact that each match ends with /, which it replaces by /test
mkdir *(/e:REPLY+=/test:)

答え3

シェルが拡張しようとしているため動作しませんみんな*/testまだ存在しない文字列です。デフォルトでは、文字列は独自に拡張されます。 Bashを使用している場合は、さまざまな内容を確認したい場合があります。ワイルドカードオプション好きな方法で処理してください。

関連情報