観察する:
$ ls
$ ls > list
$ cat list
list
ls
これは、ファイルに対してリダイレクトを実行したときにlist
すでに起動され、list
ファイルが作成されたことを示すようです。とにかく、それは十分に良い説明ですが、質問は:どのようにこれが起こらないようにすることができますか?私が期待するのは、ls
その出力を実行してダンプすることですがlist
、これが私が望むものです。
答え1
ご存知のように、ファイルはls
実行前に作成されます。これは、シェルが作業順序を処理する方法によるものです。するために
ls > file
ケーシングが必要作る file
次にstdoutがそれを指すように設定し、最後にプログラムを実行しますls
。
したがって、いくつかのオプションがあります。
- 別のディレクトリ(たとえば)にファイルを作成し、
/tmp
最終mv
ディレクトリにコピーします。 - 隠しファイル()にして
.file
名前を変更します。 grep
出力からファイルを削除するために使用されます。- だまされる:-)
不正行為は次のとおりです。
x=$(ls) ; printf "%s\n" "$x" > file
その結果、出力が変数に保存ls
され、それが作成されます。
答え2
出力ファイルは開始前にシェルによってls
生成されます。次の方法を使用してこの問題を解決できますtee
。
ls | tee list
いかなる競争条件も完全に克服するには、常に
ls | grep -vx 'list' > list
または、必要に応じてtee
結果を表示できます。
ls | grep -vx 'list' | tee list
しかし、コメントで指摘したように、ファイル名に奇妙な文字が含まれると、このような問題が発生することがよくあります。 Unixファイル名にはNUL
and以外の任意の文字を含めることができるため、/
出力を解析するのはls
非常に困難です。
- ファイル名が1つ以上
\n
。 grep
クエリが間にある場合、フィルタリングは失敗します\n
。NUL
代わりに\n
ファイル名を区別することができますが、find
それを既存のソートされた改行区切り出力のようなものに変換するのは難しいかもしれませんls
。- 出力ファイル名がすでに存在する場合は、リストから削除するのが正しくない可能性があります。
したがって、実際に動作する唯一の方法は、出力ファイルを別の場所に作成してその場所に移動することです。絶対に使用しない場合は、ls -a
次のように動作します。
ls > .list && mv .list list
ls -a
thenを使用すると、.list
出力には表示されますが、ディレクトリには存在しなくなる可能性があります。たとえば、/tmp
中間結果を保存するために別のディレクトリを使用します。もちろん、常に使用すると問題が発生するため、/tmp
スクリプトを書くことができます。
#!/bin/sh
OUTDIR='/tmp'
if [ "${PWD}" = '/tmp' ]; then
OUTDIR="${HOME}"
fi
ls > "${OUTDIR}/list" && mv "${OUTDIR}/list" list
ただし、これはこれと比較して複雑すぎるようです。
しかし、問題の完全な原因は、コマンドが開始される前にシェルが出力ファイルを生成することです。私たちはこれを考慮して、シェルに私たちのためにファイルをリストさせることができます。もしそうなら、まったく必要ありませんls
!
printf '%s\n' * > list
これは、ディレクトリに引数リストに収まらないファイルが多すぎるまで機能します。
答え3
あなたはそれを使用することができますmoreutils
sponge
:
ls | sponge list
または以下を使用してzsh
:
cp =(ls) list
GNUの使用ls
:
ls -I list > list
(以前にファイルが呼び出された場合は、そのlist
ファイルがリストされていないことを意味します。)
出力はとにかくソートされるので、ls
次のものを使用することもできます(ファイル名に改行文字が含まれていないと仮定)。
ls | sort -o list
または、二重ソートを避けるためにnsortedをls
サポートしている場合(一部の実装には他のものに対するaがあることに注意してください):-U
U
ls
-U
ls -U | sort -o list
答え4
クレジットの一部/ほとんどは@StephenHarrisに渡されます…
echo "`ls`" > list
等しい
echo "$(ls)" > list