Bashスクリプトの基本を理解できません。ここに私がこれまで持っているものがあります:
#!/bin/bash
FILES="/home/john/my directory/*.txt"
for f in "${FILES}"
do
echo "${f}"
done
私がやりたいのは、for
ループ内のすべての.txt
ファイルを一覧表示することだけです。ただし、my directory
内のスペースと*.txt
内のアスタリスクがうまく機能していません。変数名に中括弧を付けても付けなくても、二重引用符を付けても付けなくても使用しようとしましたが、すべての.txt
ファイルを印刷できません。
これは非常に基本的なことですが、疲れていて直感が持てないので、まだ苦労しています。
何が悪いのですか?
ファイルにスペースまたはアスタリスクがない場合、上記のスクリプトを正常に適用できました...機能させるには、二重引用符と中括弧を使用するか使用しないかを実験する必要がありました。しかし、スペースとアスタリスクの両方があると、すべてが混乱します。
引用符の中では、*
はファイルのリストに展開されません。このようなワイルドカードを正常に使用するには、引用符の外にある必要があります。
ワイルドカードが展開されたとしても、式"${FILES}"
は、ファイルのリストではなく、単一の文字列になります。
機能する1つのアプローチは次のとおりです。
#!/bin/bash
DIR="/home/john/my directory/"
for f in "$DIR"/*.txt
do
echo "${f}"
done
上記では、スペースやその他の難しい文字を含むファイル名は正しく処理されます。
より高度なアプローチでは、bash配列を使用できます。
#!/bin/bash
FILES=("/home/john/my directory/"*.txt)
for f in "${FILES[@]}"
do
echo "${f}"
done
この場合、FILES
はファイル名の配列です。定義を囲む括弧は、それを配列にします。 *
は引用符の外にあります。コンストラクト"${FILES[@]}"
は特殊なケースです。各文字列がファイル名の1つである文字列のリストに展開されます。スペースやその他の難しい文字を含むファイル名は正しく処理されます。
John1024で示されているように配列を使用することはより理にかなっていますが、ここでは、split + glob演算子を使用することもできます(スカラー変数は引用符で囲まずに残します)。
その演算子のglob部分だけが必要なため、split部分を無効にする必要があります。
#! /bin/sh -
# that also works in any sh, so you don't even need to have or use bash
file_pattern="/home/john/my directory/*.txt"
# all uppercase variables should be reserved for environment variables
IFS='' # disable splitting
for f in $file_pattern # here we're not quoting the variable so
# we're invoking the split+glob operator.
do
printf '%s\n' "$f" # avoid the non-reliable, non-portable "echo"
done
できることは、ワイルドカード文字のみを引用符の外に残すことです。
何かのようなもの:
in "スペースのあるファイル" * "。txt"
行う
処理
完了
ワイルドカード自体がスペースに展開される場合、ls -lを使用してファイルのリストを生成し、bash読み取りを使用して各ファイルを取得するなど、ファイルごとのアプローチを使用する必要はありません。