私は、vezult [1] によって提案されたコマンドで遊んでいたときに、自分のコンピューターに大混乱をもたらしました。ワンライナーがファイル名の削除を要求することを期待していました。ただし、フォルダー内のファイルをすぐに削除しました。
> find ./ -type f | while read x; do rm "$x"; done
stdin:s [2]の入力を待つことを期待していました。その行動が理解できません。read コマンドはどのように機能し、どこで使用しますか?
私は、vezult [1] によって提案されたコマンドで遊んでいたときに、自分のコンピューターに大混乱をもたらしました。ワンライナーがファイル名の削除を要求することを期待していました。ただし、フォルダー内のファイルをすぐに削除しました。
> find ./ -type f | while read x; do rm "$x"; done
stdin:s [2]の入力を待つことを期待していました。その行動が理解できません。read コマンドはどのように機能し、どこで使用しますか?
そこで何が起こったのかというread
と、 から読み取りますstdin
。パイプの最後に置くと、そのパイプから読み取ります。
だからあなたの発見は
file1
file2
等々; read
それを読み取り、thenにx
連続して置き換えるため、ループは次のようになりますfile1
file2
rm "ファイル1" rm "ファイル2"
案の定、rmは現在のディレクトリ "." から始まるすべてのファイルです。
いくつかのヒント。
「/」は必要ありませんでした。と言った方が安全で安心です
find . -type f
" . /
" (ドット スペース スラッシュ) と入力すると、現在のディレクトリから検索が開始され、ルート ディレクトリから検索が開始されるためです。そのトリックは、適切な権限があれば、コンピューター内のすべてのファイルを削除します。" .
" はすでにディレクトリの名前です。スラッシュを追加する必要はありません。
あなたがやりたかったことは、現在のディレクトリ " " から始まるすべてのディレクトリ内のすべてのファイルを.
調べ、それを削除するかどうかを尋ねることだったようです。あなたはそれを行うことができます
find . -type f -exec rm -i {} \;
また
find . -type f -ok rm {} \;
ループはまったく必要ありません。あなたもできる
rm -r -i *
ディレクトリも削除しようとすることを除いて、ほぼ同じ効果が得られます。ディレクトリが空の場合でも機能します。
別の考え考えてみると、大量のファイルがない限り、次のこともできます
rm -i `find . -type f`
これで、逆引用符で囲まれた検索はコマンド ラインで一連のファイル名になり、' -i
' インタラクティブ フラグをオンrm
にすると、yes または no の質問が表示されます。
チャーリー・マーティンは、あなたの特定の例で何がうまくいかなかったのかについて、適切な分析と説明を提供しますが、次の一般的な質問には対処していません。
その答えは、あるファイル (パイプライン内の前のコマンド シーケンスの標準出力である可能性が非常に高い) から連続する行を読み取りたい場合、行をいくつかの個別の変数に分割する可能性があるということです。分割は、' ' の現在の値を使用して行われます$IFS
。これは通常、空白とタブを意味します (改行はこのコンテキストではカウントされません。改行は行を区切ります)。読み取りコマンドに複数の変数がある場合、最初の単語が最初の変数に、2 番目の単語が 2 番目の変数に、...、行の残りが最後の変数に格納されます。変数が 1 つしかない場合は、行全体がその変数に入ります。
多くの用途があります。これは、分割オプションを使用する、私が持っているより単純なスクリプトの 1 つです。
#!/bin/ksh
#
# @(#)$Id: mkdbs.sh,v 1.4 2008/10/12 02:41:42 jleffler Exp $
#
# Create basic set of databases
MKDUAL=$HOME/bin/mkdual.sql
ELEMENTS=$HOME/src/sqltools/SQL/elements.sql
cat <<! |
mode_ansi with log mode ansi
logged with buffered log
unlogged
stores with buffered log
!
while read dbs logging
do
if [ "$dbs" = "unlogged" ]
then bw=""; cw=""
else bw="-ebegin"; cw="-ecommit"
fi
sqlcmd -xe "create database $dbs $logging" \
$bw -e "grant resource to public" -f $MKDUAL -f $ELEMENTS $cw
done
ヒアドキュメントを含むコマンドのcat
出力はパイプに送信されるため、出力はwhile read dbs logging
ループに入ります。最初の単語は$dbs
、作成する (Informix) データベースの名前です。行の残りは $logging に配置されます。ループの本体は、ログに記録されていないデータベース (wherebegin
およびcommit
do not work) を処理し、プログラムを実行してsqlcmd
(同名の Microsoft の新参者とは完全に別のものです。1990 年頃から存在しています)、データベースを作成し、それにデータを入力します。いくつかの標準テーブルとデータ - Oracle ' dual
' テーブルのシミュレーション、および「要素のテーブル」に関連する一連のテーブル。
このコマンドを使用する他のスクリプトread
は (はるかに) 大きくなりますが、通常、1 つ以上のファイル名と関連する他の属性を含む行を読み取り、その属性を使用してファイルに適切な変換を適用します。
Osiris JL: file * | grep 'sh.*script' | sed 's/:.*//' | xargs wgrep read
esqlcver:read version letter
jlss: while read directory
jlss: read x || exit
jlss: read x || exit
jlss: while read file type link owner group perms
jlss: read x || exit
jlss: while read file type link owner group perms
kb: while read size name
mkbod: while read directory
mkbod:while read dist comp
mkdbs:while read dbs logging
mkmsd:while read msdfile master
mknmd:while read gfile sfile version notes
publictimestamp:while read name type title
publictimestamp:while read name type title
Osiris JL:
'Osiris JL: ' は私のコマンド ライン プロンプトです。これを「bin」ディレクトリで実行しました。' wgrep
' は、単語全体にのみ一致する grep の変形です ('already' などの単語を避けるため)。これは、私がそれをどのように使用したかを示すものです。
' read x || exit
' 行は、標準入力から応答を読み取る対話型スクリプト用ですが、コマンドが EOF を取得すると終了します (たとえば、標準入力が から来る場合/dev/null
)。