次のことをしたいのですが、パイプの終わり以降に変数は保存されません。
fs=( )
echo ${fs[@]}
ls -A1 |
while read f
do
echo ${fs[@]}
fs+=( "$f" )
echo ${fs[@]}
done
echo "All files/dirs: "${fs[@]}
現在のディレクトリのファイル 1、2、3 には、次の出力が表示されます。
# Output:
1
1
1 2
1 2
1 2 3
All files/dirs:
パイプラインが終了した後にfs変数の値を保持する方法は?
修正する:
- ファイルを隠す必要があるため、*は使用できません。
- fs=($(ls)) のみ使用できず、時にはファイル/ディレクトリ名にスペースがあります。
答え1
シェルのディレクトリにあるすべてのファイルを一覧表示するのは簡単です*
。
for f in *; do …
配列(bash、ksh、zsh)をサポートするシェルでは、ファイルのリストを配列変数に直接割り当てることができます。fs=(*)
これは使用に適さないドットファイルを無視しますls -A
。 bashはdotglob
最初にドットファイルを含むようにオプションを設定するか、nullglob
現在のディレクトリが空の場合は空の配列を設定します。
shopt -s dotglob nullglob
fs=(*)
kshではを使用しますFIGNORE=".?(.)"; fs=(~(N)*)
。 zshはD
and N
glob修飾子を使用しますfs=(*(DN))
。他のシェルではこれは難しいです。最良のオプションは、各パターン*
(非ドットファイル)、.[!.]*
(シングルドットファイル、自己除外および.
二重ドットファイル)、および..?*
(二重ドットファイル、..
自己除外)を含むことです。空です。
set -- *; [ -e "$1" ] || shift
set .[!.]* "$@"; [ -e "$1" ] || shift
set ..?* "$@"; [ -e "$1" ] || shift
for x; do … # short for for x in "$@"; do …
あなたの試みにどのような問題があるかを説明することをお勧めします。主な問題は、パイプの各端が子プロセスで実行されるため、ループの割り当てが子プロセスfs
で発生し、親プロセスに渡されないことです。 (これはbashを含むほとんどのシェルの場合です。2つの例外はATT kshとzshです。パイプの右側は親シェルで実行されます。)外部サブプロセスを開始してスケジュールすることでこれを観察できます。対応する親印刷プロセスID1'2:
sh -c 'echo parent: $PPID'
{ sh -c 'echo left: $PPID >/dev/tty'; echo $? >/dev/null; } |
{ sh -c 'echo right: $PPID >/dev/tty'; echo $? >/dev/null; }
さらに、コードには2つの安定性の問題があります。
- 出力を解析しないでください
ls
。 read
必要な行を解析するためにスペースとバックスラッシュを分離します。while IFS= read -r line; do …
実際に行を解析して結果を使用する必要がある場合は、データ処理全体をブロックに入れます。
producer … | {
while IFS= read -r line; do
…
done
consumer
}
1 何も表示
しませ$$
ん。これはデフォルトのシェルプロセスのプロセスIDであり、サブシェルでは変更されません。
²
一部のbashバージョンでは、sh
bashは外部プロセスへの呼び出しを最適化するため、パイプの片側でのみ呼び出すと同じプロセスIDが表示されることがあります。中かっこ毛羽はecho $?
この最適化を無効にします。
答え2
このコードはあなたの要件を満たしています -
#!/bin/sh
echo *
一体ここで何をしたいですか?
あなたもできます。
var=*
echo $var
さらに必要な場合は、stackoverflowに移動することをお勧めします。
答え3
本当にチューブが必要ですか?これは簡単に行えます。
fs=( )
echo ${fs[@]}
for file in `ls`
do
echo $file
fs+=$file
done
echo $fs
echo "All files/dirs: "${fs[@]}