Linux 시스템에 두 개의 열이 있는 텍스트 파일이 있습니다.
- 1열 = id_no(대부분 5자리, 일부는 6자리);
- 열 2 = Genetic_markers(전체 길이 50674비트);
12345 0102010205
54322 2221110051
123456 1122011510
파일을 다음과 같이 변경하고 싶습니다.
12345 0 1 0 2 0 1 0 2 0 5
54322 2 2 2 1 1 1 0 0 5 1
123456 1 1 2 2 0 1 1 5 1 0
첫 번째 열을 숫자에 표시된 대로 오른쪽에 정렬되도록 어떻게 변경할 수 있나요?
두 번째 열의 숫자 사이의 공백을 변경하는 가장 안정적인 방법을 알려줄 수 있는 사람이 있습니까? 코드의 요소와 그 기능을 설명해주세요.
감사해요
답변1
그리고 perl
:
$ perl -lane 'printf "%6s %s\n", $F[0], join " ", split "", $F[1]' <your-file
12345 0 1 0 2 0 1 0 2 0 5
54322 2 2 2 1 1 1 0 0 5 1
123456 1 1 2 2 0 1 1 5 1 0
-lane
( 를 사용 -n
하면 한 번에 하나의 레코드를 읽고 wk가 행을 필드로 분할 하고 레코드에서 ine 구분 기호를 제거하기 때문에 -e
레코드를 사용하여 표현식을 실행합니다 .) 다음과 같이 작동합니다.$_
-a
a
@F
-l
l
perl
awk
여기서는 printf
공백을 사용하여 첫 번째 필드의 길이를 6으로 왼쪽 채운 다음 join
공백을 사용하여 두 번째 필드를 문자 구성 요소로 분할합니다.
답변2
오른쪽 정렬을 하려면 파일에서 가장 긴 숫자의 길이를 찾거나, 그냥 큰 숫자를 골라서 사용하면 됩니다. 예를 들어, 10개의 공백을 채울 수 있습니다.
$ printf '%d\n' 123
123
$ printf '%10d\n' 123
123
이 접근 방식이 충분하다면 다음을 수행할 수 있습니다.
$ awk '{ gsub(/./," &",$2); printf "%10d%s\n",$1,$2}' file
12345 0 1 0 2 0 1 0 2 0 5
54322 2 2 2 1 1 1 0 0 5 1
123456 1 1 2 2 0 1 1 5 1 0
여기서는 두 가지 일만 일어나고 있습니다.
gsub(/./," &",$2);
: 이것gsub
(G글로벌아들.
stitution) 함수는 사용자가 제공한 정규 표현식의 모든 항목을 사용자가 제공한 대체 항목으로 대체합니다(여기에서는 "모든 문자"라는 의미만 부여합니다).&
"정규 표현식과 일치하는 모든 것"을 의미하는 특별한 의미를 가지므로&
대체 효과는 각 문자 앞에 공백을 삽입하는 것입니다. 마지막 매개변수는 입력이며 여기서는 두 번째 필드를 제공합니다$2
.printf "%10d %s\n",$1,$2
printf
: 형식화된 문자열을 인쇄하는 데 사용합니다 .%10d
이는 "내가 준 숫자를 인쇄하고 10개의 공백으로 채웁니다"를 의미하며%s
이는 "이 문자열을 인쇄합니다"를 의미합니다. 그래서 우리는 10개의 공백으로 채워진 첫 번째 필드를 인쇄한 다음 수정된 두 번째 필드를 인쇄하도록 지시합니다gsub
.
최소값만 채우려면 파일을 두 번 읽어야 합니다. 먼저 가장 긴 첫 번째 필드의 길이를 가져옵니다.
$ awk -v max=0 '{ if(length($1) > max){ max=length($1) }} END{print max}' file
6
이를 통해 더 구체적으로 설명할 수 있습니다.
$ awk '{ k=gsub(/./," &",$2); printf "%6d%s\n",$1,$2}' file
12345 0 1 0 2 0 1 0 2 0 5
54322 2 2 2 1 1 1 0 0 5 1
123456 1 1 2 2 0 1 1 5 1 0
답변3
awk
any 및 GNU 사용 column
(용 -R
):
$ awk '{gsub(/./," &",$2)} 1' file | column -tR1
12345 0 1 0 2 0 1 0 2 0 5
54322 2 2 2 1 1 1 0 0 5 1
123456 1 1 2 2 0 1 1 5 1 0
-o' '
필드 사이의 공백이 정말로 중요하다면 다음을 추가하세요.
$ awk '{gsub(/./," &",$2)} 1' file | column -o' ' -t -R1
12345 0 1 0 2 0 1 0 2 0 5
54322 2 2 2 1 1 1 0 0 5 1
123456 1 1 2 2 0 1 1 5 1 0
답변4
사용행복하다(이전 Perl_6)
~$ raku -ne '.split(" ") andthen put sprintf("%6d", .[0]), .[1].comb;' file
#OR
~$ raku -ne '.words andthen put sprintf("%6d", .[0]), .[1].comb;' file
Raku는 Perl 계열의 프로그래밍 언어입니다. 위는 Raku의 -ne
비자동 인쇄 라인별 플래그를 사용합니다. 기본적으로 이 -n
플래그는 줄 끝에서 구분 기호를 제거합니다. 그런 다음 print
후행 개행 문자(기본값)를 생략하거나 , 이렇게 put
하면 후행 개행 문자가 추가됩니다(put
종결자를 사용하여 인쇄).
첫 번째 답변에서 그 줄은 분명히 .split
단일 공백(의 약어 $_.split
)에 있습니다. 두 번째 답변에서는 Raku의 .words
루틴을 공백으로 분할하는 데 사용합니다. 그런 다음 각 열의 출력 형식을 지정할 수 있도록 연결이 andthen
다시 로드됩니다 . $_
첫 번째 열(예: .[0]
)은 형식이 지정 sprintf
되고 두 번째 열(예: .[1]
)은 comb
단일 문자로 편집되어 반환됩니다.
참고: "ID"가 실제로 (10진수) 부호 없는 정수인 경우 내부적 으로 에 표시된 대로 대신 sprintf
사용할 수 있습니다 .u
d
sprintf("%6u", …)
입력 예:
12345 0102010205
54322 2221110051
123456 1122011510
예제 출력:
123450 1 0 2 0 1 0 2 0 5
543222 2 2 1 1 1 0 0 5 1
1234561 1 2 2 0 1 1 5 1 0
참고: 파일에 빈 줄이 포함되어 있을 때 오류 발생을 방지하려면 if
빈 줄을 제거하는 조건을 추가할 수 있습니다.
~$ raku -ne 'if .chars { .words andthen put sprintf("%6d", .[0]), .[1].comb};' file
#OR
~$ raku -ne 'if $_ .= words {put sprintf("%6d", .[0]), .[1].comb};' file
빈 줄을 유지하려면 Raku's를 사용할 수 있습니다.3위안운영자:
~$ raku -ne '.chars ?? ( .split(" ") andthen put sprintf( "%6d", .[0]), .[1].comb) !! "".put;' file
#OR
~$ raku -ne '$_ .= split(" ", :skip-empty) ?? (put sprintf( "%6d", .[0]), .[1].comb) !! "".put;' file
https://docs.raku.org/routine/sprintf
https://docs.raku.org/routine/%3F%3F%20%21%21
https://raku.org