最近のファイルのマージ

最近のファイルのマージ

特定のディレクトリのbashから最新のファイルから最も古いファイルまでマージするコマンドを取得したいと思います。これは、最新の日付のファイルが前の日付のファイルの前に保存されることを意味します。

答え1

zshシェルでは、ワイルドカードパターンとワイルドカード修飾子は修正タイム*(.om)スタンプに従ってソートされ、現在のディレクトリにある一般ファイルのすべての名前に展開されます。最後に変更されたファイルは結果リストの最初のエントリです。ディレクトリに通常のファイルがない場合、このモードはシェルでエラーを生成します。

zshしたがって、シェルでは

cat ./*(.om) >Save.txt

または、何千ものファイルにループを使用します。

for name ( ./*(.om) ) cat $name >Save.txt

以下でこのコマンドを呼び出しますbash

zsh -c 'for name ( ./*(.om) ) cat $name >Save.txt'

次の組み込みバリアントzargsinを使用することもできます。zshxargs

autoload -U zargs
zargs -- ./*(.om) -- cat -- >Save.txt

からbash

zsh -c 'autoload -U zargs; zargs -- ./*(.om) -- cat -- >Save.txt'

答え2

次のファイルがあると仮定すると、単にこれを行うことができます。

$ cat a.txt 
a
$ cat b.txt 
b
$ cat c.txt 
c
$ ls -lt *.txt
-rw-rw-r-- 1 user user 2 oct  7 09:21 a.txt
-rw-rw-r-- 1 user user 2 oct  7 09:21 b.txt
-rw-rw-r-- 1 user user 2 oct  7 09:21 c.txt

次に、次のコマンドを実行します。

$ ls -1t *.txt | xargs -I {} cat "{}" > Save.txt
$ cat Save.txt 
a
b
c
  • ls -1tファイル名のみをリストします。
  • xargs -I {} cat "{}"cat引数として渡された各ファイルに対してaを実行します。

もう1つ重要な注意:なぜいいえ解析ls(および実行方法)?

答え3

これを行うにはいくつかの方法がありますが、シェル構文と汎用ユーティリティのみを使用したい場合は、最良の方法の1つはfind(for(オプションの場合)および(-printfオプションの場合)、使用することです。sortsed-zxargs-0

find . -maxdepth 1 -type f -printf '%T@\t%p\0' |
  sort -z -r -n -k 1,1 |
  sed -z -e 's/^[^\t]*\t//' |
  xargs -0r cat > merged.txt

これは、以下を含むファイル名に対して機能します。どの;スペース、タブ、改行を含む有効な文字、、、、および<->などのシェルで使用される文字は、使用できる唯一の文字です|&いいえファイル名に有効なのは NUL 文字です。これがファイル名区切り文字として使用される理由です(そして信頼できる唯一のファイル名区切り文字である理由も同様です)。

findコマンドは、修正時間(エポック以降の秒)%T@とタブ文字%t、ファイル名自体、およびNUL文字が前に付けられた現在のディレクトリのすべてのファイル名を出力します。これは基本的に-print0タイムスタンプとファイル名の拡張です。この-maxdepth 1オプションは現在のディレクトリにのみ制限されます。つまり、サブディレクトリに再帰しないように指示します。

sort次に、タイムスタンプに基づいてファイル名を逆順に並べ替えるためにパイプに接続し、ファイル名の前のタイムスタンプを削除するsedためにパイプに接続し、最後にSTDINxargscat取得したすべてのファイル名にパイプに接続します。出力がにリダイレクトされますmerged.txt


ちなみに、FreeBSDまたはMacを使用している場合、FreeBSDfindもこれをサポートし、そのバージョン-printfのsedにはあります。残念ながら、そのバージョンのsedはそれをサポートしていないので、他のものを使用する必要があります。 Itとオプションを使用すると、非常に似たように動作するためです。たとえば、上記のパイプの代わりに次のようにします。sort-zxargs-0-zperl-p-nsedsed

perl -0 -p -e 's/^[^\t]*\t//'

または単にGNUをインストールしてくださいsed

しかし、LinuxでPerlを使用しない特別な理由はありません。 sedはPerlより小さく、単純で、開始オーバーヘッドが少し少ないということです。これは現代のシステムではマイナーな違いです。


または、次の場所で作業全体を完了することもできますperl

$ perl -e '@ARGV = sort { (stat($b))[9] <=> (stat($a))[9] } @ARGV;
    while (<>) {
      if ($ARGV eq "merged.txt") { close(ARGV); next } ; # skip to next file
      print
    }' -- * > merged.txt

statここで、Perlはファイル名引数をタイムスタンプで並べ替えます(修正タイムスタンプのある配列を10番目の要素として返す組み込み関数を使用するため、[9]Perl配列は1ではなく0で始まるため、これを使用します。参照perldoc -f stat)。 .... リダイレクト先の「merged.txt」を除外します。本質的に、これはcatPerlの再実装です。

高度なバージョンでは、-o outputfileオプションまたは同様のオプションを使用して独自の出力ファイルを開き(ソートする前に@ARGVから出力ファイル名を削除します - すでに存在し、globと一致する場合*)、出力をハードコーディングする必要はありません。ファイル書き込み除外コードです。

#!/usr/bin/perl

use Getopt::Std;

getopts('o:', \%opts);
$opts{o} = '/dev/stdout' unless defined($opts{o}); # default to stdout
# alternatively, you could print an error message to STDERR and exit:
# die "-o option is required\n" unless defined($opts{o});

@ARGV = grep { ! /^$opts{o}$/ } @ARGV;
@ARGV = sort { (stat($b))[9] <=> (stat($a))[9] } @ARGV;

open($out,">",$opts{o});
while (<>) {
  print $out $_;
};
close($out);

$PATHのどこかに保存できます(現在のディレクトリにあることを望まないか、出力に含めます。これを防ぐためのいくつかの方法がありますが、スクリプトは単純なものより少し長くなります。たとえば、必須はより複雑です。以下をchmod使用して実行可能にします。

merge.pl -o merged.txt -- *

注:、grepおよびstat上記sortは組み込みのPerl関数です。いいえコマンドラインユーティリティ。で詳細情報を入手できますperldoc -f

関連情報