回答:
lsの出力を解析しないでください!lsの出力の解析は難しく、信頼性がありません。
これを行う必要がある場合は、findを使用することをお勧めします。もともと私はあなたにソリューションの要点を伝えるために単純な例を持っていましたが、この答えはある程度一般的であるため、これを修正してすべての入力でコピー/貼り付けして使用できる安全なバージョンを提供することにしました。快適に座っていますか?現在のディレクトリにある最新のファイルを提供するonelinerから始めます。
tail -- "$(find . -maxdepth 1 -type f -printf '%T@.%p\0' | sort -znr -t. -k1,2 | while IFS= read -r -d '' -r record ; do printf '%s' "$record" | cut -d. -f3- ; break ; done)"
ワンライナーではありませんか?ここでもシェル関数として、読みやすいようにフォーマットされています。
latest-file-in-directory () {
find "${@:-.}" -maxdepth 1 -type f -printf '%T@.%p\0' | \
sort -znr -t. -k1,2 | \
while IFS= read -r -d '' -r record ; do
printf '%s' "$record" | cut -d. -f3-
break
done
}
そして今、その onelinerとして:
tail -- "$(latest-file-in-directory)"
他のすべてが失敗した場合、上記の関数をに含めて、.bashrc
1つの警告で解決された問題を検討できます。仕事をやりたいだけなら、これ以上読む必要はありません。
これに関する注意点は、1つ以上の改行で終わるファイル名がまだtail
正しく渡されないことです。この問題を回避することは複雑であり、このような悪意のあるファイル名に遭遇した場合、より危険なものではなく、「No such file」エラーに遭遇する比較的安全な動作が発生すれば十分と考えます。
好奇心が強い人にとっては、これがどのように機能するのか、なぜ安全なのか、他の方法がおそらくそうでないのかについての退屈な説明です。
まず第一に、ファイルパスを区切るのに安全な唯一のバイトは、Unixシステムのファイルパスで一般的に禁止されている唯一のバイトであるため、nullです。ファイルパスのリストを処理するときは、区切り文字としてnullのみを使用し、あるプログラムから別のプログラムに単一のファイルパスを渡すときは、任意のバイトでチョークしない方法で行うことが重要です。ファイル名に新しい行やスペースが含まれないと仮定することで(偶然でも)失敗する、この問題やその他の問題を解決する多くの正しい方法があります。どちらの仮定も安全ではありません。
今日の目的のためのステップ1は、ヌル区切りのファイルのリストを検索から取得することです。GNUなどのfind
サポートがある場合、これは非常に簡単です-print0
。
find . -print0
しかし、このリストはまだどれが最新のものかを教えていないので、その情報を含める必要があります。findの-printf
スイッチを使用して、出力に表示するデータを指定できます。find
サポートのすべてのバージョン-printf
(標準ではありません)ではありませんが、GNU findはサポートしています。自分がいない-printf
ことに気付いた場合、標準ではないので-exec stat {} \;
、どの時点で移植性のすべての希望をあきらめる必要stat
があります。とりあえず、GNUツールを持っていると仮定して話を進めます。
find . -printf '%T@.%p\0'
ここで%T@
は、Unixエポックの始まりからピリオドが続き、その後に秒の小数部を示す数字が続く、秒単位の変更時間であるprintf形式を要求しています。これに別のピリオドを追加してから%p
(ファイルへのフルパス)、ヌルバイトで終了します。
今私が持っています
find . -maxdepth 1 \! -type d -printf '%T@.%p\0'
言うまでもありませんが、完全であるために、サブディレクトリの内容を一覧表示する-maxdepth 1
ことを防ぎfind
、\! -type d
あなたがしたくないと思われるディレクトリをスキップしますtail
。これまでのところ、現在のディレクトリに変更時刻情報を含むファイルがあるため、その変更時刻で並べ替える必要があります。
デフォルトでsort
は、入力は改行で区切られたレコードであると想定されます。GNU sort
をお持ちの場合は、-z
スイッチを使用して代わりにヌル区切りのレコードを期待するように依頼できます。標準sort
では解決策はありません。私は最初の2つの数字(秒と秒の小数)でソートすることにのみ興味があり、実際のファイル名でソートしたくないので、sort
2つのことを伝えます:最初に、ピリオド(.
)をフィールド区切り文字と見なす必要があること次に、レコードの並べ替え方法を検討するときに、最初と2番目のフィールドのみを使用する必要があること。
| sort -znr -t. -k1,2
まず、価値のない3つの短いオプションをまとめています。-znr
簡潔な言い方です-z -n -r
)。その後-t .
(スペースはオプション)sort
、フィールド区切り文字に-k 1,2
指示し、フィールド番号を指定します:最初と2番目(sort
ゼロではなく1からフィールドをカウントします)。現在のディレクトリのサンプルレコードは次のようになります。
1000000000.0000000000../some-file-name
この手段は、sort
最初のを見ていきます1000000000
と、その後0000000000
、このレコードを注文するとき。この-n
オプションはsort
、これらの値を比較するときに数値比較を使用するように指示します。両方の値が数値であるためです。数字の長さが固定されているため、これは重要ではないかもしれませんが、害はありません。
与えられた他のスイッチsort
は-r
「リバース」用です。デフォルトでは、数値ソートの出力は最小値が最初に-r
なり、最小値が最後に、最大値が最初にリストされるように変更されます。これらの数値はタイムスタンプであるため、値が大きいほど新しいことになり、最新のレコードがリストの先頭に配置されます。
ファイルパスのリストが表示されるsort
と、目的の答えが最上部に表示されます。残っているのは、他のレコードを破棄し、タイムスタンプを削除する方法を見つけることです。残念ながら、GNU head
でさえtail
、ヌル区切りの入力で動作させるためのスイッチを受け入れません。その代わりに、whileループを一種の貧乏人として使用しますhead
。
| while IFS= read -r -d '' record
まずIFS
、ファイルのリストが単語分割の対象にならないように設定を解除します。次に、read
2つのことを説明します。入力内のエスケープシーケンスを解釈しないでください-r
(-d
)。入力はヌルバイト()で区切られています。ここでは、空の文字列''
を使用して、「区切り文字なし」別名nullで区切られています。各レコードは変数に読み込まれるrecord
ため、while
ループが繰り返されるたびに、単一のタイムスタンプと単一のファイル名が使用されます。これ-d
はGNU拡張機能であることに注意してください。標準がある場合、read
この手法は機能せず、頼りになることはほとんどありません。
record
変数には3つの部分があり、すべてピリオド文字で区切られていることがわかっています。cut
ユーティリティを使用して、それらの一部を抽出することができます。
printf '%s' "$record" | cut -d. -f3-
ここでは、レコード全体printf
がそこにパイプされcut
、そこからパイプされます。bashでは、パフォーマンスを向上させるためにhere文字列を使用してこれをさらに簡略化できますcut -d. -3f- <<<"$record"
。cut
2つのことを説明します。まず、-d
フィールドを識別するための特定の区切り文字を使用する必要があります(sort
区切り文字.
が使用される場合と同様)。2番目cut
は-f
、特定のフィールドの値のみを印刷するように指示されています。フィールドリストは3-
、3番目のフィールドと後続のすべてのフィールドの値を示す範囲として指定されます。つまりcut
、2番目までのすべてを読み取り、無視します。.
、レコード内で見つかっ、残り(ファイルパス部分)を出力ます。
最新のファイルパスを出力すると、続行する必要はありませんbreak
。2番目のファイルパスに移動させずにループを終了します。
残っているのはtail
、このパイプラインによって返されたファイルパスで実行されていることだけです。私の例では、パイプラインをサブシェルで囲むことでこれを行ったことに気付いたかもしれません。気付いていないかもしれませんが、サブシェルを二重引用符で囲んでいます。これは重要なことです。最後に、すべてのファイル名に対して安全であるためのこの努力のすべてでさえ、引用されていないサブシェル拡張はまだ物事を壊す可能性があるからです。より詳細な説明は、あなたが興味を持っている場合は可能です。呼び出しの2番目に重要だが見過ごされやすい側面tail
は--
、ファイル名を展開する前にオプションを提供したことです。これは指示しますtail
これ以上オプションが指定されておらず、それに続くすべてがファイル名であるため、で始まるファイル名を安全に処理できます-
。
tail -f $(find . -type f -exec stat -f "%m {}" {} \;| sort -n | tail -n 1 | cut -d ' ' -f 2)
head
でさえtail
、ヌル区切りの入力で動作させるスイッチを受け入れません。」私の代わりhead
:… | grep -zm <number> ""
。
tail `ls -t | head -1`
スペースを含むファイル名が心配な場合は、
tail "`ls -t | head -1`"
次を使用できます。
tail $(ls -1t | head -1)
$()
構築物は、コマンド実行し、サブシェルを開始しls -1t
ていることや配管(時間順、1行に1つずつのすべてのファイルを一覧表示)head -1
最初の行(ファイル)を取得するために。
次に、そのコマンドの出力(最新のファイル)が渡されtail
て処理されます。
作成された最新のディレクトリエントリである場合、これによりディレクトリを取得するリスクが生じることに注意してください。エイリアスでそのトリックを使用して、これらのログファイルのみを含むディレクトリ内の最新のログファイル(ローテーションセットから)を編集しました。
-1
は必要でls
はありません。パイプの中にあるときにそれを行います。比較ls
してls|cat
、例えば。
POSIXシステムでは、「最後に作成された」ディレクトリエントリを取得する方法はありません。各ディレクトリエントリにはatime
、mtime
およびctime
がありますが、Microsoft Windowsとは異なり、これctime
はCreationTimeではなく「最終ステータス変更の時間」を意味します。
ですから、あなたが得ることができる最善の方法は、「最後に変更されたファイルの末尾」です。これは他の回答で説明されています。私はこのコマンドに行きます:
tail -f "$(ls -tr | sed 1q)"
ls
コマンドを囲む引用符に注意してください。これにより、スニペットはほぼすべてのファイル名で機能します。
でzsh
:
tail *(.om[1])
参照:http : //zsh.sourceforge.net/Doc/Release/Expansion.html#Glob-Qualifiers、ここでm
は変更時刻を示しm[Mwhms][-|+]n
、前述のo
方法は、1つの方法でソートされることを意味します(O
他の方法でソートする)。これ.
は通常のファイルのみを意味します。括弧内[1]
で最初のアイテムを選択します。3つの使用を選択し[1,3]
、最も古い使用を取得します[-1]
。
短くて便利で、を使用しませんls
。
シンプルな:
tail -f /path/to/directory/*
私にとってはうまくいきます。
問題は、tailコマンドを開始した後に生成されるファイルを取得することです。ただし、それが必要でない場合(上記のすべての解決策では問題にならないため)、アスタリスクは単純な解決策であるIMOです。
誰かがそれを投稿し、何らかの理由でそれを消去しましたが、これが唯一の機能するので、...
tail -f `ls -tr | tail`
ls
ことは最も賢明なことではないことに同意するため、削除しました...-
tail -f `ls -lt | grep -v ^d | head -2 | tail -1 | tr -s " " | cut -f 8 -d " "`
説明: