空白+変数を持つL

空白+変数を持つL

次のことをしたいのですが、パイプの終わり以降に変数は保存されません。

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

出力を解析しないでくださいls

シェルのディレクトリにあるすべてのファイルを一覧表示するのは簡単です*

for f in *; do …

配列(bash、ksh、zsh)をサポートするシェルでは、ファイルのリストを配列変数に直接割り当てることができます。fs=(*)

これは使用に適さないドットファイルを無視しますls -A。 bashはdotglob最初にドットファイルを含むようにオプションを設定するか、nullglob現在のディレクトリが空の場合は空の配列を設定します。

shopt -s dotglob nullglob
fs=(*)

kshではを使用しますFIGNORE=".?(.)"; fs=(~(N)*)。 zshはDand Nglob修飾子を使用します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つの安定性の問題があります。

実際に行を解析して結果を使用する必要がある場合は、データ処理全体をブロックに入れます。

producer … | {
  while IFS= read -r line; do
  done
  consumer
}

1 何も表示 しませ$$ん。これはデフォルトのシェルプロセスのプロセスIDであり、サブシェルでは変更されません。
² 一部のbashバージョンでは、shbashは外部プロセスへの呼び出しを最適化するため、パイプの片側でのみ呼び出すと同じプロセスIDが表示されることがあります。中かっこ毛羽はecho $?この最適化を無効にします。

おすすめ記事