'date -d @xxxxxx'및 'find ./'명령을 연결하는 방법은 무엇입니까?


14

1970-01-01 이후 밀리 초 단위로 이름이 타임 스탬프 인 디렉토리가 있습니다.

1439715011728
1439793321429
1439879712214
.
.

그리고 다음과 같은 출력이 필요합니다.

1442039711    Sat Sep 12 08:35:11 CEST 2015
1442134211    Sun Sep 13 10:50:11 CEST 2015
1442212521    Mon Sep 14 08:35:21 CEST 2015
.
.

명령으로 모든 디렉토리를 나열 할 수 있습니다.

find ./ -type d | cut -c 3-12

그러나 다음 명령에 출력을 넣을 수 없으며 출력을 date -d @xxxxxx조작 할 수 없습니다 .

어떻게해야합니까?


2
이러한 타임 스탬프는 어떻게 에포크 (epoch)로 변환됩니까? 당신의 숫자가 너무 오래이기 때문에 (즉, 첫 번째 -입니다 Fri Oct 2 05:35:28 47592)
Sobrique

1
@Sobrique 신기원부터 분명히 밀리 초.
Gilles 'SO- 악의를 멈춰라'

답변:


10

올바른 길을 가고 있습니다 (2 ~ 3 개의 명령 만 실행하는 간단한 솔루션은 아래 참조). 당신은 현재 디렉토리를 제거하기 위해 *대신에 사용해야 합니다 ./¹ 이것은 밀리 초의 절단을 약간 단순화 한 다음 결과를 GNU parallel또는 xargs² 로 파이프하면됩니다 :

find * -type d | cut -c 1-10 | parallel date --date=@{} +%c

얻을

Sat 12 Sep 2015 08:35:11 CEST
Sun 13 Sep 2015 10:50:11 CEST
Mon 14 Sep 2015 08:35:21 CEST

예제에서 알 수 있듯이 초 오프셋을 추가하려면 다음을 수행하십시오.

find * -type d | cut -c 1-10 | parallel 'echo "{} "  $(date --date=@{} +%c)'

또는:

find * -type d | cut -c 1-10 | xargs -I{} bash -c 'echo "{} "  $(date --date=@{} +%c)'

얻을 :

1442039711  Sat 12 Sep 2015 08:35:11 CEST
1442134211  Sun 13 Sep 2015 10:50:11 CEST
1442212521  Mon 14 Sep 2015 08:35:21 CEST

그러나 다음과 같이하는 것이 더 간단합니다 :

find * -type d -printf "@%.10f\n" | date -f - +'%s  %c'

동일한 요청 출력을 한 번 더 가져옵니다.

사용의 단점은 *확장을 위해 명령 줄에 의해 제한된다는 것입니다. 그러나 장점은 디렉토리를 타임 스탬프 값으로 정렬한다는 것입니다. 디렉토리 수가 문제가있는 경우을 사용 -mindepth 1하지만 순서를 잃어 버리십시오.

find ./ -mindepth 1 -type d -printf "@%.10f\n" | date -f - +'%s  %c'

sort필요한 경우 삽입 하십시오.

find ./ -mindepth 1 -type d -printf "@%.10f\n" | sort | date -f - +'%s  %c'

¹ 여기에서는 예제와 같이 중첩 된 하위 디렉토리가 없다고 가정합니다. 당신은 또한 사용할 수 있습니다 ./ -mindepth 1대신*
² 당신은 대체 할 수 parallel와 함께 xargs -I{}그것은 단지 더 자세한, @hobbs로 여기 @don_crissti은 제안했다. ³ 파일 읽기 기능 을 사용하는 Gilles의 답변을 기반으로 함date


또는 xargs없는 경우 parallel많은 사람이없는 것 같습니다.
hobbs

@hobbs AFAIK는 xargs인수가 같이가는 위치를 지정하는 옵션이 없습니다 parallel에있다 {}.
Anthon

4
그것은 않습니다find ./ -type d | cut -c 3-12 | xargs -I{} date --d @{} +'%Y-%m-%d'
don_crissti

@Anthon은 -I옵션 을 사용하면 가능합니다.
hobbs

1
@Anthon, GNU 긴 옵션은 모호하지 않은 한 축약 될 수 있습니다. --d또는 --daGNU의 현재 버전과 함께 작동합니다 date,하지만 하루 작동하지 않을 수 있습니다 date소개하는 --dalek(달렉 달력에서 날짜) 옵션을 선택합니다.
Stéphane Chazelas

10

루프에서 파일 당 여러 명령을 실행하지 마십시오. 이미 GNUisms를 사용하고 있기 때문에 :

find . ! -name . -prune -type d |
  awk '{t = substr($0, 3, 10); print t, strftime("%a %b %d %T %Z %Y", t)}'

두 명령 만 실행합니다. strftime()처럼 GNU 고유의 것 date -d입니다.


이것은 디렉토리 이름의 밀리 초를 자르지 않지만 요청 된 처음 10 개 대신 13 자 전체를 표시합니다.
Anthon

@Anthon은 그렇습니다. 지금은 괜찮을 것입니다.
Stéphane Chazelas

8

넌 이미 가지고있다:

find ./ -type d | cut -c 3-12

아마 당신에게 시대 형식의 타임 스탬프를 얻을 수 있습니다. 이제 while 루프를 추가하십시오 :

find ./ -type d | cut -c 3-12 | while read datestamp
do
    printf %s "$datestamp"
    date -d "@$datestamp"
done

일부 셸에서 해당 구문은 하위 셸에서 while 루프를 가져옵니다. 즉, 변수를 설정하려고하면 루프를 떠난 후에는 표시되지 않습니다. 그것을 고치려면 머리에 물건을 약간 돌려야합니다.

while read datestamp
do
    printf %s "$datestamp"
    date -d "@$datestamp"
done < <(find ./ -type d | cut -c 3-12)

find서브 쉘에 넣고 while 루프를 메인 쉘에 유지합니다. 그 구문 (AT & T ksh, zsh그리고 bash당신은하지만, 루프 내부에서 그 결과를 다시 사용하고자하는 경우 특정는)에만 필요합니다.


상관없이, 그것은 bash 특정이라고 말하는 것이 맞지 않습니다 :)
Wouter Verhelst

실제로, 처음에 썼던 done <(find)대신 , 대신 ( 프로세스 대체가 아닌 프로세스 리디렉션이 있는 곳 ) done < <(find)정확했습니다 . 따라서 내 편집은 의도 한 쉘 일 수 있었으므로 약간 무심했습니다. yash<(...)
Stéphane Chazelas

6

GNU 날짜가있는 경우 입력 파일에서 읽은 날짜를 변환 할 수 있습니다. 타임 스탬프를 조금만 마사지하면 인식 할 수 있습니다. 유닉스 시대를 기반으로 한 타임 스탬프의 입력 구문 @은 소수점을 포함 할 수있는 초 수입니다.

find ./ -type d ! -name '*[!0-9]*' |
sed -e 's~.*/~@~' -e 's~[0-9][0-9][0-9]$~.&~' |
date -f - +'%s  %c'

date파일 읽기 사용에 +1 이것은을 줄 것 date: invalid date ‘@’때문에 현재 디렉토리의 번역의 ( ./). 그리고 밀리 초를 버릴 수 있으므로 두 번째 sed편집을 단순화 하여 마지막 3자를 드롭 할 수 있습니다 . 아니면 모두 제거하고 사용하십시오find * -type d -printf "@%.10f" | date ...
Anthon

5

타임 스탬프 목록을 피드로 제공합니다.

#!/usr/bin/perl
use strict;
use warnings;
use Time::Piece;

while ( my $ts = <DATA> ) { 
   chomp ( $ts );
   my $t = Time::Piece->new();
   print $t->epoch, " ", $t,"\n";
}

__DATA__
1442039711  
1442134211  
1442212521

이 결과는 다음과 같습니다.

1442039711 Sat Sep 12 07:35:11 2015
1442134211 Sun Sep 13 09:50:11 2015
1442212521 Mon Sep 14 07:35:21 2015

특정 출력 형식을 원하면 다음과 같이 사용할 수 있습니다 strftime.

print $t->epoch, " ", $t->strftime("%Y-%m-%d %H:%M:%S"),"\n";

파이프에서 하나의 라이너로 바꾸는 것 :

 perl -MTime::Piece -nle '$t=Time::Piece->new($_); print $t->epoch, "  ", $t, "\n";'

그러나 아마도 대신 File::Find모듈 을 사용하고 대신 펄에서 모든 일을하는 것이 좋습니다. 자르기 전에 디렉토리 구조의 예를 제시하면 예를 들어 보겠습니다. 그러나 다음과 같습니다.

#!/usr/bin/env perl

use strict;
use warnings;
use Time::Piece;
use File::Find; 

sub print_timestamp_if_dir {
   #skip if 'current' item is not a directory. 
   next unless -d; 
   #extract timestamp (replicating your cut command - I think?)
   my ( $timestamp ) = m/.{3}(\d{9})/; #like cut -c 3-12;

   #parse date
   my $t = Time::Piece->new($timestamp);
   #print file full path, epoch time and formatted time; 
   print $File::Find::name, " ", $t->epoch, " ", $t->strftime("%Y-%m-%d %H:%M:%S"),"\n";
}

find ( \&print_timestamp_if_dir, "." ); 

2

zsh의 strftime의 내장 :

zmodload zsh/datetime
for d (*(/))
strftime '%s %a %b %d %T %Z %Y' $d

이것은 현재 디렉토리의 모든 디렉토리 이름이 실제로 획기적인 시간이라고 가정합니다.
예제에서 해당 숫자를 처리하는 방법을 명확히하면 추가 필터링 / 처리가 가능합니다 (Leia와 Luke Skywalker의 생년월일에 해당하는 에포크 시간과 유사 함). 예를 들어 최소한 일치하는 디렉토리 이름을 재귀 적으로 검색합니다. 10 자리 숫자를 입력하고 처음 10 자리를 기준으로 날짜를 계산하십시오.

setopt extendedglob
zmodload zsh/datetime
for d (**/[0-9](#c10,)(/))
strftime '%s %a %b %d %T %Z %Y' ${${d:t}:0:10}

2

GNU Parallel 사용하기 :

find ./ -type d | cut -c 3-12 | parallel -k 'echo {} `date -d @{}`'

공백 대신 \ t를 사용할 수있는 경우 :

find ./ -type d | cut -c 3-12 | parallel -k --tag date -d @{}

참고 parallel로 작성된 것입니다 perl. 이것은 연산자 perl가 있다고 생각하면 과도하게 보입니다 strftime(). 처럼perl -MPOSIX -lpe '$_.=strftime(" %c", localtime substr $_, 2, 10)'
Stéphane Chazelas

2
1. 짧습니다. 2. Perl을 배울 필요가 없습니다.
Ole Tange

1
그것은 27 % 더 짧지 만 몇 배나 덜 효율적입니다 (테스트에서 약 800 배 느립니다. 쉘 (/ bin / sh가 아닌 쉘)과 각 줄에 대한 날짜 명령을 생성해야 함을 고려하십시오) 한 번에 모든 CPU에 부담을 주므로 시스템에 친숙하지 않습니다. 그리고 당신은 여전히 ​​배워야 parallel합니다. IMO parallel는 CPU를 많이 사용하는 작업을 병렬화하는 훌륭한 도구이지만 여기서는 이런 종류의 작업에는 적합하지 않습니다.
Stéphane Chazelas

거기는 여전히 허용 솔루션 그래서 효율, 중요하지 않은 상황이 많이 있지만, 그 생각, 특히 그것은 여전히 성능 문제를 언급 할 가치가 평행 일반적으로 운율 고성능 사람들의 마음이다.
Stéphane Chazelas

0

일반적으로 find 명령은 exec인수를 사용하는 모든 명령과 연결될 수 있습니다 .

귀하의 경우 다음과 같이 할 수 있습니다 :

find . -type d | cut -c 3-12 | while read line
do
       echo -n "${line}  "
       date -d $line
done

0

파이썬 사용하기 (가장 느린 해결책입니다)

for i in $(ls -A); do echo $i | xargs python -c "from sys import argv;from time import strftime;from datetime import datetime;print datetime.fromtimestamp(float(argv[1][:-3])).strftime('%Y-%m-%d %H:%M:%S'),'---',argv[1]"; done

제공합니다 :

2015-08-30 08:48:59 --- 1440917339340
2015-08-31 08:00:22 --- 1441000822458
2015-09-01 08:00:32 --- 1441087232437
2015-09-01 16:48:43 --- 1441118923773
2015-09-02 08:00:11 --- 1441173611869
2015-09-03 08:00:32 --- 1441260032393
2015-09-04 08:00:21 --- 1441346421651

파이썬에서 왜 모두하지 않습니까? 많은 파이프를 연결하는 대신?
Sobrique

더 나은 의미가 있습니다. 나는 동의한다.
lukaz
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.