최근 파일 병합

최근 파일 병합

특정 디렉터리의 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를 실행합니다.

한 가지 더 중요한 참고 사항:아니요구문 분석 ls(및 수행 방법)?.

답변3

이를 수행하는 방법은 여러 가지가 있지만 쉘 구문과 일반 유틸리티만 사용하려는 경우 가장 좋은 방법 중 하나는 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파일 이름 앞의 타임스탬프를 제거하기 위해 파이프로 연결되며, 마지막으로 STDIN xargs에서 cat얻은 모든 파일 이름 으로 파이프로 연결됩니다. 출력이 로 리디렉션됩니다 merged.txt.


그건 그렇고, FreeBSD 또는 Mac을 사용하는 경우 FreeBSD find도 이를 지원하며 해당 -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 -- *

참고: , grepstatsort의 내용은 내장된 Perl 함수입니다.아니요명령줄 유틸리티. 를 통해 자세한 정보를 얻을 수 있습니다 perldoc -f.

관련 정보