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
?上記の例に反映されていない理由があると思います。)
ファイル名に改行文字が含まれている場合、状況ははるかに難しくなります。この場合、どうすべきかは扱いません。改行文字は含まれていないが他のスペースを含めることができる場合は、-l
onフラグを省略し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
。