複数の「人」に対して動作するスクリプトを実行し、各人の出力ファイルとエラーファイルを生成します。これをこう表現してみよう:
output_alice.txt
error_alice.txt
output_bob.txt
error_bob.txt
.
.
.
error_<name>.txt
スクリプトがエラーで終了した「人」をすばやく識別できるように、すべてのファイルからエラー()を検索し、コンテンツが記録されたファイル(空のファイルではない)をエコーするコマンドが必要です。見つけることができるショートカットがありますか?私はgrepを使って文字列(例えば)でこれを行う方法を知っていますが、grep -r <substring> .
そこに何があるかどうかを確認する方法はわかりません。
答え1
bashはそうではありません。端末、それは多くのものの一つですシェルこれは、コマンドの実行に特化した特定のプログラミング言語の通訳です。ほとんどのアプリケーションと同様に、入力/出力を端末デバイスまたは他の種類のファイルに接続できます。
bashおよび他のほとんどのUnixシェル言語で、現在の作業ディレクトリにl
1つ以上の名前付き行を含むファイルを一覧表示するには、次のようにします。error_anything.txt
grep -l '^' error_*.txt
^
トピックの先頭に一致する正規表現はどこにありますか?トピックファイルの各行はですgrep
。
空でないテキスト行が1つ以上ある人の場合:
grep -l . error_*.txt
ここでは.
単一文字と一致します。ロケールとは異なる文字マップエンコーディングを使用するファイルは、その内容をテキストとしてデコードできない場合、空でない行と一致しない可能性があります。
また、すべてのgrep
実装が終了していない行が1つだけ含まれるファイルを報告するわけではありません(の出力に示すように、1つは行区切り文字がありませんprintf invalid-text-as-missing-the-last-newline
)。
別の方法は、少なくとも1バイトを含むファイルを見つけることです。
find -L . ! -name . -prune -name 'error_*.txt' -type f -size +0c
これは、そのタイプではないファイルを無視するという利点もあります。定期的な(例:ディレクトリ、ソケット...)
またはzshシェルを使用してください。
print -rC1 -- error_*.txt(N-.L+0)
シンボリックリンクの場合、動作はターゲットのサイズと種類を考慮してullglobの動作と同じです(ullglobの場合、-
一致するファイルがないとエラーは報告されません)。-L
.
-type f
L+0
-size +0c
N
N
これはプレフィックスを含まないという利点があり、./
ユーザー名をロケールのテキストにデコードできない場合にも機能し、(語彙的に)ソートされたリストを提供します。
r
これを拡張して、ユーザー名(最初の名前の後のファイルoot名部分_
)のみを印刷できます。
{}{ print -rC1 -- ${@#*_}; } error_*.txt(N-.L+0:r)
error
コマンドの実行後に変更されたファイルを一覧表示するには、コマンドを-newer
実行する前に編集したファイルの述語を使用してfind
比較できます。touch
touch .before
my-command-that-may-write-to-error-files
find -L . ! -name . -prune -name 'error_*.txt' -type f -size +0c -newer .before
find
zshでは、コマンドを次のように置き換えることができます。
print -rC1 -- error_*.txt(N-.L+0e['[[ $REPLY -nt .before ]]'])
一部の実装では、置き換えることfind
ができますが、深さ0()のファイルは他の基準と一致しないため、ここでも機能します(一致も一致も一致しません)。! -name . -prune
-mindepth 1 -maxdepth 1
-maxdepth 1
.
-name 'error_*.txt'
-type f
date
andのGNU実装(述語を導入した実装find
でもある)を使用すると、次のようにしてこのファイルの生成を回避できます。find
-maxdepth
.before
before=$(date +'@%s.%N')
my-command-that-may-write-to-error-files
find -L . -maxdepth 1 -name 'error_*.txt' -type f -size +0c -newermt "$before"
を使用するとき、または(後に)にzsh
置き換えることができます。再呼び出しを避けることができます。before=$(date +'@%s.%N')
print -Pv before '@%D{%s.%N}'
before=${(%):-@%{%s.%N}D}
before=@$EPOCHREALTIME
zmodload zsh/datetime
find
グローバル予選また、一時変数に匿名関数を再利用することもありますが、これは非常に複雑になります。
zmodload zsh/stat
zmodload zsh/datetime
() {
my-command-that-may-write-to-error-files
print -rC1 error_*.txt(N-.L+0e['
stat -F %s.%N -A2 +mtime -- $REPLY && (( $2 > $1 )) '])
} $EPOCHREALTIME
少なくともLinuxでは、システムとファイルシステムはナノ秒精度をサポートしますが、粒度ははるかに小さいです。初期呼び出しdate
または参照より前の値を変更するときは変更時間が設定されているため、$EPOCHREALTIME
実行に100分の1秒もかからないコマンドではこの方法が機能しない可能性があります。 1秒を削除しN
てそれを>
またはに置き換える方が良い方法かもしれません(実装がサポートしている場合は可能ではありません)。>=
-newer
! -older
find
答え2
GNU は空のfind
ファイルをリストする POSIX 以外のオプションを提供します。テストを無効にするだけです。
find /path/to/dir -type f -name 'error_*.txt' ! -empty
~のためいいえ-maxdepth 1
検索するパスの後にサブディレクトリを追加します。
POSIXではfind
ファイルサイズの確認が0
可能です。
find /path/to/dir -type f -name 'error_*.txt' ! -size 0
答え3
grep for は.
すべての文字を意味します。空のファイルには文字がないため、検索時に空でない.
ファイルが表示されます。たとえば、
$ touch empty1 empty2 empty3
$ echo "not empty!" > non_empty
$ ls -l
total 4
-rw-r--r-- 1 terdon terdon 0 Aug 11 13:13 empty1
-rw-r--r-- 1 terdon terdon 0 Aug 11 13:13 empty2
-rw-r--r-- 1 terdon terdon 0 Aug 11 13:13 empty3
-rw-r--r-- 1 terdon terdon 11 Aug 11 13:13 non_empty
今、私たちは以下をgrepします。
$ grep -- . ./*
non_empty:not empty!
そして名前を調べてください。
$ grep -l -- . ./*
non_empty
grep .
空白行(1文字以上)を持たないファイルは見つかりません\n
。これを行うには、grep '^'
提案どおりに使用する必要があります。スティーブンの答え。
答え4
GNU sed専用です。次のコマンドの代替と同様にgrep
:
sed -sn 1F error_*.txt
!F
マニュアルページでコマンドが見つかりませんでしたが、うまくいきます。特に、空でないファイルの最初の行にファイル名を挿入します。sed -i 1F *