파일의 에포크 타임 스탬프를 다른 형식으로 바꾸는 방법은 무엇입니까?


10

나는 인간이 읽을 수 있도록 변환 해야하는 시대를 포함하는 파일이 있습니다. 날짜 변환을 수행하는 방법을 이미 알고 있습니다. 예 :

[server01 ~]$ date -d@1472200700
Fri 26 Aug 09:38:20 BST 2016

.. 그러나 sed파일을 살펴보고 모든 항목을 변환 하는 방법을 알아 내려고 고심하고 있습니다. 파일 형식은 다음과 같습니다.

#1472047795
ll /data/holding/email
#1472047906
cat /etc/rsyslog.conf
#1472048038
ll /data/holding/web

1
나중에 참조 할 수 있도록 (이 파일이 Bash 히스토리 파일이라고 가정하면 파일과 유사 함) HISTTIMEFORMAT작성시 형식을 제어 하기 위해 쉘 변수를 확인하십시오.
Toby Speight

@Toby HISTTIMEFORMAT의 값은 (stdout으로) 표시 할 때 사용되지만 HISTFILE을 작성할 때는 상태 (null과 unset로 설정 됨) 만 중요합니다.
dave_thompson_085

@ dave 덕분에, 나는 그것을 알지 못했습니다 (역사 시간의 사용자가 아닙니다).
Toby Speight

date -d솔직히 솔라리스라고 말할 수 없습니다 ... 나는 이것이 대부분 GNU 도구를 가진 시스템에 있다고 가정하고 있습니까? (GNU AWK / Perl은 날짜 변환을 처리하기에 더 휴대하기 쉬운 방법입니다). gawk '{ if ($0 ~ /^#[0-9]*$/) {print strftime("%c",substr($0,2)); } else {print} }' < file( strftime휴대용이 아닌 것 같습니다 ...)
Gert van den Berg

답변:


6

일관된 파일 형식을 가정하면 bash파일을 한 줄씩 읽고 주어진 형식인지 테스트 한 다음 변환을 수행 할 수 있습니다.

while IFS= read -r i; do [[ $i =~ ^#([0-9]{10})$ ]] && \
      date -d@"${BASH_REMATCH[1]}"; done <file.txt

BASH_REMATCH는 첫 번째 요소가 정규식 일치의 첫 번째 캡처 된 그룹 인 배열이며이 =~경우에는 에포크입니다.


파일 구조를 유지하려는 경우 :

while IFS= read -r i; do if [[ $i =~ ^#([0-9]{10})$ ]]; then printf '#%s\n' \
   "$(date -d@"${BASH_REMATCH[1]}")"; else printf '%s\n' "$i"; fi; done <file.txt

수정 된 내용을 STDOUT에 출력하여 파일에 저장합니다. 예 out.txt:

while ...; do ...; done >out.txt

원하는 경우 원본 파일을 바꿀 수 있습니다.

mv out.txt file.txt

예:

$ cat file.txt
#1472047795
ll /data/holding/email
#1472047906
cat /etc/rsyslog.conf
#1472048038
ll /data/holding/web

$ while IFS= read -r i; do [[ $i =~ ^#([0-9]{10})$ ]] && date -d@"${BASH_REMATCH[1]}"; done <file.txt
Wed Aug 24 20:09:55 BDT 2016
Wed Aug 24 20:11:46 BDT 2016
Wed Aug 24 20:13:58 BDT 2016

$ while IFS= read -r i; do if [[ $i =~ ^#([0-9]{10})$ ]]; then printf '#%s\n' "$(date -d@"${BASH_REMATCH[1]}")"; else printf '%s\n' "$i"; fi; done <file.txt
#Wed Aug 24 20:09:55 BDT 2016
ll /data/holding/email
#Wed Aug 24 20:11:46 BDT 2016
cat /etc/rsyslog.conf
#Wed Aug 24 20:13:58 BDT 2016
ll /data/holding/web

니스 .... 변환 된 날짜를 화면에 인쇄합니다. 이제 파일의 항목을 바꾸라는 명령을 어떻게 얻습니까?
기계 기술자

@machinist 내 편집 내용 확인 ..
heemayl

1
당신의 최신 버전을 사용하는 경우 bash, printf변환 자체를 수행 할 수 있습니다 printf '#%(%F %H)T\n' "${BASH_REMATCH[1]}".
chepner

14

GNU에서 가능한 sed것은 다음과 같습니다.

sed -E 's/^#([0-9]+).*$/date -d @\1/e'

이는 사실상 비효율적이며 (임의의 명령 삽입 취약점 1 을 도입하기 쉽다 ) 이는 사실상 루프 만큼 나쁜date#xxxx라인 에 대해 하나의 쉘과 하나의 명령을 실행하는 것을 의미 하기 때문 이다. 여기서는 날짜 변환 기능이 내장 된 텍스트 처리 유틸리티 인 or 와 같은 것을 사용하는 것이 좋습니다 .while readperlgawk

perl  -MPOSIX -pe 's/^#(\d+).*/ctime $1/se'

또는:

gawk '/^#/{$0 = strftime("%c", substr($0, 2))};1'

(1) 우리는 쓴 경우 ^#([0-9]).*대신 ^#([0-9]).*$같은 입력과, (표준 요즘) UTF-8 것과 같은 멀티 바이트 로케일에서 다음 (나는이 답변의 이전 버전에서했던 것처럼), #1472047795<0x80>;reboot즉, <0x80>바이트 값 0x80으로 인 유효한 문자를 구성하지 않으면 해당 s명령이 date -d@1472047795<0x80>; reboot예를 들어 실행되었을 수 있습니다 . extra가있는 동안 $해당 줄은 대체되지 않습니다. 다른 방법은 다음과 같습니다 s/^#([0-9])/date -d @\1 #/e. 즉, #xxx날짜 이후 부분을 쉘 주석으로 남겨 둡니다 .


1
무엇 단지 사용에 대한 의 단일 인스턴스date -f 스트림 현명한 방식으로 변환 모든 수행하는가?
Digital Trauma

perl 명령은 ctime $ 1 후에 새 줄을 추가하는 것으로 보이며 제거 할 방법을 찾을 수 없습니다.
Alex Harvey

1
@ 알렉스. 권리. 편집을 참조하십시오. s플래그를 추가하면 .*입력시 줄 바꿈도 포함됩니다. 을 사용할 수도 있습니다 strftime "%c", localtime $1.
Stéphane Chazelas

@ StéphaneChazelas 너무 감사합니다. 좋은 답변입니다.
Alex Harvey

3

다른 모든 답변은 date변환해야 할 모든 시대에 대해 새로운 프로세스를 생성합니다 . 입력이 큰 경우 성능 오버 헤드가 발생할 수 있습니다.

그러나 GNU 날짜에는 -f단일 프로세스 인스턴스가 date새로운 포크없이 입력 날짜를 지속적으로 읽을 수 있는 편리한 옵션이 있습니다 . 우리가 사용할 수 있도록 sed, paste그리고 date이러한 방식으로 각각의 단지 (2 배에 한 번 산란 도착하도록 sed관계없이 입력이 얼마나 큰의) :

$ paste -d '\n' <( sed '2~2d;y/#/@/' epoch.txt | date -f - ) <( sed '1~2d' epoch.txt )
Wed Aug 24 07:09:55 PDT 2016
ll /data/holding/email
Wed Aug 24 07:11:46 PDT 2016
cat /etc/rsyslog.conf
Wed Aug 24 07:13:58 PDT 2016
ll /data/holding/web
$ 
  • sed명령은 기본적으로 입력의 짝수 및 홀수 줄을 삭제합니다. 첫 번째는 대체 #와 함께 @올바른 시대의 타임 스탬프 형식을 제공 할 수 있습니다.
  • sed그런 다음 첫 번째 출력이 date -f수신되는 모든 입력 라인에 대해 필요한 날짜 변환을 수행합니다.
  • 이 두 스트림은를 사용하여 단일 필수 출력으로 인터레이스됩니다 paste. <( )구조는 bash는 프로세스 대체 효과적으로 출력 명령 내부에서 파이프 읽는 사실상 때 주어진 파일 이름에서 읽고 생각으로 붙여 트릭. -d '\n'지시 paste개행으로 홀수 및 짝수 라인 출력을 분리. 예를 들어 다른 텍스트와 같은 줄에 타임 스탬프를 원하는 경우이를 변경 (또는 제거) 할 수 있습니다.

이 명령에는 몇 가지 GNUism과 Bashism이 있습니다. 이것은 Posix와 호환되지 않으며 GNU / Linux 외부에서 이식 가능하지 않아야합니다. 예를 들어 date -fOSXes BSD date변형 에서 다른 작업을 수행 합니다.


date -d(질문에서) 또한 이식 가능하지 않습니다 ... (FreeBSD에서는 DST 설정을 엉망으로 만들려고 시도합니다. Solaris에서는 오류가 발생합니다 ...) 질문은 OS를 지정하지 않습니다 ...
Gert van den Berg

@GertvandenBerg 예, 이것은이 답변의 마지막 단락에서 해결됩니다.
Digital Trauma

난 아스 커의 샘플도 (그들은 아마 OS를 ... 태그해야) 이식성 문제를 ... 가지고 있다는 것을 의미
게르트 반 덴 베르그

1

게시물에있는 날짜 형식이 원하는 것으로 가정하면 다음 정규식이 필요에 맞아야합니다.

sed -E 's/\#(1[0-9]{9})(.*)/echo \1 $(date -d @\1)/e' log.file

이것은 라인 당 하나의 에포크 만 대체한다는 사실을 명심하십시오.


이 명령으로 다음과 같은 오류가 발생합니다. sed: -e expression #1, char 48: invalid reference \3 on 's' command's RHS
machinist

1
내 실수로 게시물을 수정했습니다.
Hatclock

0

sed 사용 :

sed -r 's/\#([0-9]*)/echo $(date -d @\1)/eg' test.txt

출력 :

ر أغس 24 16:09:55 EET 2016
ll /data/holding/email
ر أغس 24 16:11:46 EET 2016
cat /etc/rsyslog.conf
ر أغس 24 16:13:58 EET 2016
ll /data/holding/web

내 로케일 언어가 아랍어이므로 :)


0

내 솔루션 파이프 라인에서 그렇게하는 방법

cat test.txt | sed 's/^/echo "/; s/\([0-9]\{10\}\)/`date -d @\1`/; s/$/"/' | bash
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.