사람이 읽을 수 있는 날짜로 변환해야 하는 신기원 날짜가 포함된 파일이 있습니다. 나는 이미 다음과 같이 날짜 변환을 수행하는 방법을 알고 있습니다.
[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
sed
GNU는 다음과 같은 기능을 수행할 수 있습니다 :
sed -E 's/^#([0-9]+).*$/date -d @\1/e'
이는 매우 비효율적입니다(그리고 임의의 명령 주입 취약점이 쉽게 발생합니다1 ) . 이는 사실상 다음과 같이 date
각 줄에 대해 쉘과 명령을 실행하는 것을 의미하기 때문입니다.#xxxx
쉘 while read
루프 만큼 나쁘다. 여기서는 날짜 변환 기능이 내장된 텍스트 처리 유틸리티인 perl
또는 와 같은 것을 사용하는 것이 더 좋습니다 .gawk
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
쉘 주석으로 유지하는 것입니다.
답변2
파일 형식이 일관적이라고 가정하면 bash
파일을 한 줄씩 읽고 지정된 형식인지 테스트한 다음 변환할 수 있습니다.
while IFS= read -r i; do [[ $i =~ ^#([0-9]{10})$ ]] && \
date -d@"${BASH_REMATCH[1]}"; done <file.txt
BASH_REMATCH
첫 번째 요소가 정규식 일치에서 첫 번째로 캡처된 그룹인 배열입니다( =~
이 경우 epoch).
파일 구조를 유지하려면 다음을 수행하십시오.
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
답변3
다른 모든 답변은 date
변환해야 하는 각 신기원 날짜에 대해 새로운 프로세스를 생성합니다. 입력이 크면 성능 오버헤드가 추가될 수 있습니다.
그러나 GNU 날짜에는 -f
단일 프로세스 인스턴스가 date
새 포크 없이도 입력 날짜를 지속적으로 읽을 수 있는 편리한 옵션이 있습니다. 따라서 우리는 를 사용할 수 sed
있으며 paste
입력이 아무리 크더라도 date
각 입력은 한 번만 생성됩니다(2x의 경우).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 프로세스 교체이는 Paste가 주어진 파일 이름에서 읽는다고 생각하도록 효과적으로 속입니다. 실제로는 내부 명령에서 파이프된 출력을 읽고 있습니다. 홀수 및 짝수 출력 라인을 개행 문자로 구분하도록-d '\n'
지시합니다 .paste
예를 들어 타임스탬프를 다른 텍스트와 같은 줄에 표시하려면 이 설정을 변경(또는 제거)할 수 있습니다.
이 명령에는 여러 GNUism과 Bashism이 있습니다. 이는 Posix와 호환되지 않으며 GNU/Linux 세계 외부로 이식 가능하다고 기대해서는 안 됩니다. 예를 들어 date -f
OSXes BSD 변형에서 다른 작업을 수행합니다 date
.
답변4
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
제 언어는 아랍어거든요 :)