これはbash構文の精神的な訓練に近いです。私たちが一緒に解決できるように、これをパズルだと思うように招待します。またはbashを理解するための挑戦として。
質問
たとえば、マイフォルダには3つのファイルがあります./etc
。
./etc
foo.txt.example
bar.txt.example
hello world.txt.example
(はい、このファイルにはスペースがあります)
上記のファイルに基づいてこれらのターゲットを実行するためのターゲットを構築しました。動作するタスクは次のとおりです。
make "etc/foo.txt"
make "etc/bar.txt"
make "etc/hello world.txt"
したがって、理論的には、すべてのターゲットを実行するために次のコマンドを作成できます。
make "etc/foo.txt" "etc/bar.txt" "etc/hello world.txt"
私の質問は次のとおりです。すべてを検索するbashスクリプトを書くことはできますか? ./etc/*.txt.example
ファイル名と上記のコマンドを設定しますか?
必要
- 答えはbashコマンド形式またはMakefileターゲット定義形式でなければなりません。
- ほとんどのLinux環境では、デフォルトで実行する必要があります。一般的でないパッケージをインストールする必要はありません。
私が試したこと
Makefileで上記のすべてのファイル名を取得する方法を見つけました。
txt:
for fn in "etc/*.txt.example"; do \
echo "etc/$$(basename -s ".example" "$$fn")"; \
done
これは基本的にbashで実行することを意味します。
for fn in "etc/*.txt.example"; do \
echo "etc/$(basename -s ".example" "$fn")"; \
done
次の出力を提供します。
etc/foo.txt
etc/bar.txt
etc/hello world.txt
このループの出力を別のコマンドの入力として使用すると、そのコマンドはすべてのスペースを引数の区切り文字として扱うようです。だからこれ:
make $(for fn in "etc/*.txt.example"; do \
echo "etc/$(basename -s ".example" "$fn")"; \
done)
実際には次のようになります。
make "etc/foo.txt" "etc/bar.txt" "etc/hello" "world.txt"
ループの出力を空白を正しく保持する引数に変換する方法はありますか?
答え1
配列を使用できます。
# Get all example files in an array
examples=(etc/*.example)
# Strip the .example suffix from every element of the array
make "${examples[@]%.example}"
または、GNU find、sed、および xargs がある場合 (つまり、ヌル区切り文字をサポート):
find etc -iname '*.example' -print0 | sed -z 's/\.example$//' | xargs -0 make
答え2
ヌルで区切られたファイル名のリストを作成し、次のように渡しmake
ますxargs
。
for name in /etc/*.txt.example; do
printf '%s\0' "${name%.example}"
done | xargs -0 make
答え3
まずサンプルファイルを作成してから
set etc/*.tbl.example
N="shift $#"
for arg
do
$N; N=;
set X ${1+"$@"} "$(expr "$arg" '\(.*\).example')"; shift
done
# and then...
make ${1+"$@"}