特定のディレクトリの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'
次の組み込みバリアントzargs
inを使用することもできます。zsh
xargs
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
オプションの場合)、使用することです。sort
sed
-z
xargs
-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
ためにパイプに接続し、最後にSTDINxargs
でcat
取得したすべてのファイル名にパイプに接続します。出力がにリダイレクトされますmerged.txt
。
ちなみに、FreeBSDまたはMacを使用している場合、FreeBSDfind
もこれをサポートし、そのバージョン-printf
のsedにはあります。残念ながら、そのバージョンのsedはそれをサポートしていないので、他のものを使用する必要があります。 Itとオプションを使用すると、非常に似たように動作するためです。たとえば、上記のパイプの代わりに次のようにします。sort
-z
xargs
-0
-z
perl
-p
-n
sed
sed
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」を除外します。本質的に、これはcat
Perlの再実装です。
高度なバージョンでは、-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
。