
다음 텍스트가 있습니다.
LABEL1
.BYTE 01, 02, 03, 04, 05
.BYTE 01, 02, 03
쉼표로 구분된 값 순서만 반대로 바꿔야 합니다.
LABEL1
.BYTE 05, 04, 03, 02, 01
.BYTE 03, 02, 01
다음과 같은 작업이 필요합니다.
ITINERARY_ARRAY_01
.BYTE <ITINERARY_00A
.BYTE <ITINERARY_01A
.BYTE <ITINERARY_02A
.BYTE <ITINERARY_03A
.BYTE <ITINERARY_04A
.BYTE <ITINERARY_05A
.BYTE <ITINERARY_06A
.BYTE <ITINERARY_07A
.BYTE <ITINERARY_08A
.BYTE <ITINERARY_09A
.BYTE <ITINERARY_10A
.BYTE <ITINERARY_11A
.BYTE <ITINERARY_12A
.BYTE <ITINERARY_13A
.BYTE <ITINERARY_14A
;-------------------
ITINERARY_01E
.BYTE $03, $05, $07, $00
;-------------------
ITINERARY_01F
.BYTE $03, $05, $07, $09, $00
;-------------------
ITINERARY_01G
.BYTE $28, $0D, $00
;-------------------
ITINERARY_01H
.BYTE $28, $0D, $0F, $13, $00
;-------------------
ITINERARY_01I
.BYTE $28, $0D, $0F, $11, $00
;-------------------
ITINERARY_01J
.BYTE $03, $05, $07, $09, $20, $1E, $00
;-------------------
ITINERARY_01K
.BYTE $28, $0D, $0F, $13, $15, $00
;-------------------
ITINERARY_01L
.BYTE $03, $05, $07, $09, $20, $1E, $1C, $27
.BYTE $00
;---------------------
".BYTE" 이후의 값을 제외하고는 아무것도 변경할 필요가 없습니다. 역순, 16진수 형식이어야 하며 "$"를 접두사로 사용해야 합니다... 이 "편집"에 대해 죄송하지만 지금에서만 볼 수 있습니다. 다시 한번 감사드립니다!
답변1
여기서는 다음을 수행합니다 sed
.
sed '/,/!b
s/\( *[^ ]*\)\(.*\)/\2,\n\1/;:t
s/\([^,]*,\)\(\n.*\)/\2\1/;tt
s/\n\(.*\),/\1/' <<\DATA
LABEL1
.BYTE 01, 02, 03, 04, 05
.BYTE 01, 02, 03
LABEL1
.BYTE 01, 02, 03, 04, 05
.BYTE 01, 02, 03
DATA
산출
LABEL1
.BYTE 05, 04, 03, 02, 01
.BYTE 03, 02, 01
LABEL1
.BYTE 05, 04, 03, 02, 01
.BYTE 03, 02, 01
현재 줄에 쉼표가 있는지 확인합니다. !
쉼표가 없으면 스크립트 sed
b
를 실행하고 해당 줄을 자동 인쇄합니다. 만약 라인하다쉼표 포함은 sed
다음을 수행합니다.
s///
먼저 다음을 대체 하여 행을 준비합니다 .\( *[^ ]*\)
- 0개 이상의 공백으로 이루어진 첫 번째 시퀀스 다음에 바로 다음과 같이 참조되는 0개 이상의 공백이 아닌 문자의 시퀀스가\1
바로 다음에 옵니다...\(.*\)
- 라인의 다른 모든 항목은 다음과 같이 참조됩니다\2
.- ...와 함께
\2,\n\1
- 메모- 이와 같이
\n
오른쪽 대체 필드에서 이스케이프를 사용하는 것은 완전히 이식 가능하지 않습니다. 이를 지원하지 않는s///
a의 경우 대신 명령문에서 리터럴 개행 문자를 대체하여 수행할 수 있습니다.sed
n
:
이라는 분기/테스트 레이블을 정의 합니다t
.- 여전히 가능하지만
sed
s///
대체물은 다음과 같습니다.\([^,]*,\)
- 쉼표가 아닌 0개 이상의 시퀀스그 다음에바로 뒤에 다음 과 같이 참조되는 단일 쉼표\1
...\(\n.*\)
- 적어도 하나의\n
ewline 문자로 시작하고 그 뒤에 다음과 같이 참조되는 패턴 공간에 남아 있는 모든 항목/모든 항목이 이어지는 시퀀스입니다\2
.- ...와 함께
\2\1
.
- 이전
s///
대체가t
성공 하면 est 레이블sed
로 다시 분기하여:t
다시 시도합니다. - 마지막으로
sed
약간의 정리를 수행하고 다음을 대체합니다.\n\(.*\),
- 처음으로 나타나는\n
줄줄이 문자와 마지막으로 나타나는 쉼표...\1
- ...그 사이에 모든 것이 놓여 있습니다.
sed
재귀 교체와 마찬가지로 \n
줄줄 구분 기호는 한 번에 하나의 쉼표로 구분된 필드씩 뒤로 이동합니다. \n
ewline이 줄의 첫 번째 문자일 때 교체를 중지합니다 . l
재귀 교체 프로세스의 진행 상황은 다음과 같습니다 .
01, 02, 03, 04, 05,\n .BYTE$
01, 02, 03, 04,\n .BYTE 05,$
01, 02, 03,\n .BYTE 05, 04,$
01, 02,\n .BYTE 05, 04, 03,$
01,\n .BYTE 05, 04, 03, 02,$
\n .BYTE 05, 04, 03, 02, 01,$
초기 준비 대체 후에는 sed
쉼표와 삽입된 줄 문자만 제외하고는 구분하지 않습니다 \n
. 그래서어느일종의 쉼표로 구분된 값이 잘 작동합니다. 긴 비트를 실행한 결과는 다음과 같습니다.
ITINERARY_ARRAY_01
.BYTE <ITINERARY_00A
.BYTE <ITINERARY_01A
.BYTE <ITINERARY_02A
.BYTE <ITINERARY_03A
.BYTE <ITINERARY_04A
.BYTE <ITINERARY_05A
.BYTE <ITINERARY_06A
.BYTE <ITINERARY_07A
.BYTE <ITINERARY_08A
.BYTE <ITINERARY_09A
.BYTE <ITINERARY_10A
.BYTE <ITINERARY_11A
.BYTE <ITINERARY_12A
.BYTE <ITINERARY_13A
.BYTE <ITINERARY_14A
;-------------------
ITINERARY_01E
.BYTE $00, $07, $05, $03
;-------------------
ITINERARY_01F
.BYTE $00, $09, $07, $05, $03
;-------------------
ITINERARY_01G
.BYTE $00, $0D, $28
;-------------------
ITINERARY_01H
.BYTE $00, $13, $0F, $0D, $28
;-------------------
ITINERARY_01I
.BYTE $00, $11, $0F, $0D, $28
;-------------------
ITINERARY_01J
.BYTE $00, $1E, $20, $09, $07, $05, $03
;-------------------
ITINERARY_01K
.BYTE $00, $15, $13, $0F, $0D, $28
;-------------------
ITINERARY_01L
.BYTE $27, $1C, $1E, $20, $09, $07, $05, $03
.BYTE $00
;---------------------
답변2
파일 revbytes2.awk
:
#!/usr/bin/awk -f
BEGIN {
FS=",? +"
}
NF>2 && match($0,"^ +\.BYTE ") {
printf substr($0,1,RSTART+RLENGTH-1)
for(i=NF;i>3;i--) printf $i", "
print $3
next
}
1
FS=",? +"
필드 구분 기호로 바이트 사이의 awk
공백 .BYTE
과 플러스 공백 시퀀스를 인식 합니다 .,
각 줄에 대해 공백과 공백으로 시작하는 2개 이상의 필드가 있는 줄을 찾고 표현식의 부작용으로 이 .BYTE
접두사의 시작과 길이를 기억합니다 .RSTART
RLENGTH
match(...)
일치하는 항목이 발견되고 2개 이상의 필드가 있는 경우 및를 사용하여 원래 줄에서 접두어를 잘라낸 다음 RSTART
나머지 RLENGTH
필드를 역순으로 인쇄합니다.
공백 + .BYTE
공백 접두어를 찾을 수 없거나 필드가 2개 이하인 경우 행은 그대로 인쇄됩니다. .BYTE
따라서 되돌릴 것이 없기 때문에 1바이트만 정의하는 -line 에 대해서도 이 작업이 수행됩니다 .
테스트 실행:
$ diff -u$(wc -l <input) input <(awk -f revbytes2.awk input)
--- input 2014-10-19 06:04:48.280714146 +0200
+++ /dev/fd/63 2014-10-19 22:40:01.385538235 +0200
@@ -1,42 +1,42 @@
ITINERARY_ARRAY_01
.BYTE <ITINERARY_00A
.BYTE <ITINERARY_01A
.BYTE <ITINERARY_02A
.BYTE <ITINERARY_03A
.BYTE <ITINERARY_04A
.BYTE <ITINERARY_05A
.BYTE <ITINERARY_06A
.BYTE <ITINERARY_07A
.BYTE <ITINERARY_08A
.BYTE <ITINERARY_09A
.BYTE <ITINERARY_10A
.BYTE <ITINERARY_11A
.BYTE <ITINERARY_12A
.BYTE <ITINERARY_13A
.BYTE <ITINERARY_14A
;-------------------
ITINERARY_01E
- .BYTE $03, $05, $07, $00
+ .BYTE $00, $07, $05, $03
;-------------------
ITINERARY_01F
- .BYTE $03, $05, $07, $09, $00
+ .BYTE $00, $09, $07, $05, $03
;-------------------
ITINERARY_01G
- .BYTE $28, $0D, $00
+ .BYTE $00, $0D, $28
;-------------------
ITINERARY_01H
- .BYTE $28, $0D, $0F, $13, $00
+ .BYTE $00, $13, $0F, $0D, $28
;-------------------
ITINERARY_01I
- .BYTE $28, $0D, $0F, $11, $00
+ .BYTE $00, $11, $0F, $0D, $28
;-------------------
ITINERARY_01J
- .BYTE $03, $05, $07, $09, $20, $1E, $00
+ .BYTE $00, $1E, $20, $09, $07, $05, $03
;-------------------
ITINERARY_01K
- .BYTE $28, $0D, $0F, $13, $15, $00
+ .BYTE $00, $15, $13, $0F, $0D, $28
;-------------------
ITINERARY_01L
- .BYTE $03, $05, $07, $09, $20, $1E, $1C, $27
+ .BYTE $27, $1C, $1E, $20, $09, $07, $05, $03
.BYTE $00
;---------------------
비교 mawk
및 gawk
출력:
$ diff <(mawk -f revbytes2.awk input) <(gawk -f revbytes2.awk input)
gawk: revbytes2.awk:5: warning: escape sequence `\.' treated as plain `.'
분명히 stdout에는 차이가 없습니다. 좋은!
표현식 내부 "^ +\056BYTE "
대신 쓰면 경고가 사라집니다 ."^ +\.BYTE "
match(...)
어쩌면 자주 사용하는 사람이 gawk
경고를 피하는 더 좋은 방법을 알고 있을 수도 있습니다.
답변3
내가 할 방법은 다음과 같습니다.
perl -MTie::File -e'
tie @lines,"Tie::File","your_file";
for(@lines){
next unless /,/; # Skip lines with no commas
$csv = /(\s*[^,\s]+,.*)/;
$new_csv = join ",",reverse split /,/,$csv;
s/\Q$csv/$new_csv/;
}'
부인 성명!!
파일이 수정됩니다.현장에서. 원하지 않는 경우 파일의 더미 복사본을 사용하십시오.
원본 파일을 수정하지 않는 버전
perl -pe'
next unless /,/; # Skip lines with no commas
chomp;
$csv = /(\s*[^,\s]+,.*)/;
$new_csv = join ",",reverse split /,/,$csv;
$new_csv .= "\n"; # The newline removed by chomp
s/\Q$csv/$new_csv/;
' your_file
가정
- 쉼표 주위의 간격은 신경 쓰지 않습니다.
- CSV 값 중 첫 번째 값은
.BYTE
최소한 하나의 공백만큼 오프셋됩니다. - "순서 역전"이란 숫자 순서를 내림차순으로 정렬하지 않고 파일에서 찾은 순서를 역전시키는 것을 의미합니다.
입력
ITINERARY_ARRAY_01
.BYTE <ITINERARY_00A
.BYTE <ITINERARY_01A
.BYTE <ITINERARY_02A
.BYTE <ITINERARY_03A
.BYTE <ITINERARY_04A
.BYTE <ITINERARY_05A
.BYTE <ITINERARY_06A
.BYTE <ITINERARY_07A
.BYTE <ITINERARY_08A
.BYTE <ITINERARY_09A
.BYTE <ITINERARY_10A
.BYTE <ITINERARY_11A
.BYTE <ITINERARY_12A
.BYTE <ITINERARY_13A
.BYTE <ITINERARY_14A
;-------------------
ITINERARY_01E
.BYTE $03, $05, $07, $00
;-------------------
ITINERARY_01F
.BYTE $03, $05, $07, $09, $00
;-------------------
ITINERARY_01G
.BYTE $28, $0D, $00
;-------------------
ITINERARY_01H
.BYTE $28, $0D, $0F, $13, $00
;-------------------
ITINERARY_01I
.BYTE $28, $0D, $0F, $11, $00
;-------------------
ITINERARY_01J
.BYTE $03, $05, $07, $09, $20, $1E, $00
;-------------------
ITINERARY_01K
.BYTE $28, $0D, $0F, $13, $15, $00
;-------------------
ITINERARY_01L
.BYTE $03, $05, $07, $09, $20, $1E, $1C, $27
.BYTE $00
;---------------------
산출
ITINERARY_ARRAY_01
.BYTE <ITINERARY_00A
.BYTE <ITINERARY_01A
.BYTE <ITINERARY_02A
.BYTE <ITINERARY_03A
.BYTE <ITINERARY_04A
.BYTE <ITINERARY_05A
.BYTE <ITINERARY_06A
.BYTE <ITINERARY_07A
.BYTE <ITINERARY_08A
.BYTE <ITINERARY_09A
.BYTE <ITINERARY_10A
.BYTE <ITINERARY_11A
.BYTE <ITINERARY_12A
.BYTE <ITINERARY_13A
.BYTE <ITINERARY_14A
;-------------------
ITINERARY_01E
.BYTE $00, $07, $05, $03
;-------------------
ITINERARY_01F
.BYTE $00, $09, $07, $05, $03
;-------------------
ITINERARY_01G
.BYTE $00, $0D, $28
;-------------------
ITINERARY_01H
.BYTE $00, $13, $0F, $0D, $28
;-------------------
ITINERARY_01I
.BYTE $00, $11, $0F, $0D, $28
;-------------------
ITINERARY_01J
.BYTE $00, $1E, $20, $09, $07, $05, $03
;-------------------
ITINERARY_01K
.BYTE $00, $15, $13, $0F, $0D, $28
;-------------------
ITINERARY_01L
.BYTE $27, $1C, $1E, $20, $09, $07, $05, $03
.BYTE $00
;---------------------
답변4
입력하면 다음을 사용할 수 있습니다 perl
.
$ perl -MText::Tabs -anle '
BEGIN {$tabstop = 4};
print and next if /^\S/;
@nums = grep { $_ =~ /\d+/ } @F;
map { s/\D//g } @nums;
map { $_ = (pop @nums) . (@nums==0 ? "" : ",")
if $_ =~ /\d+/ } @F;
print expand "\t@F";
' file
LABEL1
.BYTE 05, 04, 03, 02, 01
.BYTE 03, 02, 01
귀하의 원래 입력이 정렬되었다고 가정합니다. 그렇지 않은 경우 @nums = sort { $a <=> $b } grep { $_ =~ /\d+/ } @F;
대신 사용할 수 있습니다 @nums = grep { $_ =~ /\d+/ } @F;
.