変数にリストを保存する

変数にリストを保存する

781名前に含まれるファイルのリストの名前を保存しようとしています。私はこのリストで何かをし、次にこのリストを削除します。

これを行うには2つのオプションがあります。

オプション1:次のコマンドを使用してリストを一時ファイルに保存できます。

ls -lart *781* | awk '{print $9}' > tempo

ファイルにはtempoリストが含まれており、使用後にファイルを削除します。

オプション2:どういうわけかリストを変数に保存し、その変数を使用できる場合。これを達成するために以下のコードを試していますが、うまくいきません。

filelist=`ls -lart *781* | awk '{print $9}'`
echo $filelist

ただし、上記のコードは何の出力も提供しません。構文の問題を助けてください。

編集する:k-shellを使用しています。

答え1

lsファイルのリストを取得するために使用しないでください。特に、ls *これは空のディレクトリ行がたくさん提供されるため、さらにそうです。

以下を使用できます(常に良いわけではありません)。

for file in *781*; do
  echo "$file"
done

空白のあるファイルは保存されますが、他の特殊文字を持つファイルは保存されません。

次のようにすることもできます。

 find . -name "*781*" -print0 | while IFS="" read -r -d "" file; do
   echo "$file"
 done

どちらが優れていますが、すべてのUNIX(Linuxも同様)の標準ではありません。

すべての場合にスペースを区切り文字として使用することはできないため、ファイル名を単一の変数に入れないでください。おそらく、次のようにbash配列を使用できます。

declare -a file_array
while IFS="" read -r -d "" file; do
  file_array[${#file_array[@]}]="$file"
done < <(find . -print0)

プロセスの置き換えなしでkshで作業するには、次の手順を実行します。

typeset -a file_array
mkfifo mypipe
find . -print0 > mypipe &
while IFS="" read -r -d "" file; do
  file_array[${#file_array[@]}]="$file"
done < mypipe
rm mypipe

詳細については、以下を確認してください。これそしてこれ

答え2

匿名パイプのアイデアと関数の出力を配列の入力として使用する必要性からインスピレーションを得た提案によって、コプロセスが役立つことがわかりました。

MyFunction()
{ echo "One line" ; echo "Second line" ; echo "Third line" }

set -A array
MyFunction 'SomeInputToFunction' < /dev/null |&

while read -p -r line; do
    print "READING from co-process: $line"
    array[ ${#array[@]} ]="$line"
done

出力:

READING from MyFunction co-process: One line
READING from MyFunction co-process: Second line
READING from MyFunction co-process: Third line

以前のポスターに感謝します! ——フェルナンド・ゴンザレス

答え3

どのシェルを使用しているかはわかりませんが、bash

export filelist=`ls -lart *781* | awk '{print $9}'`
echo $filelist

たとえば、

export filelist=`ls -l|awk '{print $4}'`
echo $filelist
root root sys nobody sys sys sys sys root sys bin root sys root other sys sys root root sys other root sys root sys sys root root

答え4

なぜあなたの例がうまくいかないのかわかりません。ここで動作します。すべてのファイルに一致するグローバル式を使用する場合です。一致するものがディレクトリである可能性があり、そのディレクトリの内容を一覧表示したくない-d場合ls

glob式がどのファイルとも一致しないときに何が起こるのか注意してください。 Bashには有効な設定がありshopt -s failglob、この場合はエラーが発生します。他のシェルまたはbashでこのオプションが有効になっていない場合は、glob式自体が出力として表示されます。ただ実行すると、echo nonmatching_expression*「nonmatching_expression*」という結果が表示されます。これにより、ls nonmatching_expression*lsでエラーが発生します。

作成したとおり、両方のオプションがファイル名にスペースが含まれていないとします。ls -l ... | awk '{print $9}'ファイル名にスペースが含まれていない場合は問題ありません。 (しかし、なぜそれls -l ... | awk '{print $9}'を使用せずに使用しているのでしょうかls?上記の例に反映されていない理由があると思います。)

ファイル名に改行文字が含まれている場合、状況ははるかに難しくなります。この場合、どうすべきかは扱いません。改行文字は含まれていないが他のスペースを含めることができる場合は、-lonフラグを省略しlsてawkのパイプを省略できます。最初のオプションは、1行に1つのファイル名を一時ファイルに保存します。これらのファイル名にはスペースまたはタブを含めることができます(ただし、改行は含まれません)。 2番目のオプションも1行に1つのファイル名を変数に保存しますが、使用するのは難しいです。

ファイル名のリストを変数に保存し、ファイル名にスペースを含めることができる場合は、変数を展開するときに必ず変数を引用符で囲む必要があります。したがって、echo "$filelist"notを使用してくださいecho $filelist

データを抽出する方法は次のとおりです。

オプション1:

while IFS= read -r f; do
  do_stuff_with "$f"
done < tempo

オプション2:

while IFS= read -r f; do
  do_stuff_with "$f"
done << EOF
$filelist
EOF

これらのメソッドを使用すると、スクリプトの残りの部分に表示されるループ内でアクション(変数の変更、ディレクトリの変更)を実行できます。これを気にしない場合は、while ... done次のようにその部分をパイプラインに配置できます。

echo "$filelist" | while IFS= read -r f; do
  do_stuff_with "$f"
done

この場合、構成while ... done全体はサブシェルで実行され、変数(ループを含むf)に対するすべての変更はそのサブシェル内でのみ表示されます。

Bashや他のいくつかのシェルには配列変数があります。一部の人々は、ファイル名にスペースが含まれているときに使用する方が簡単だと思います。しかし、携帯性が低下します。そしてエクスポートできません。 (質問にタグを付けるのは/environment-variables変数がエクスポートされるという意味です。しかし、そういう意味ではないかもしれません。) ここでは、目的に合わせて配列変数を使用する方法について議論しません。

ファイル名にスペースがないことがわかっている場合は、最も簡単な方法はオプション2を使用することです。

for f in $filenames; do
    do_stuff_with $f
done

ここでは引用符を省略する必要があり$filenames、aroundはオプションです$f

関連情報