
지드라이브list
다음 예와 같은 파일 목록을 인쇄하는 하위 명령이 있습니다 .
gdrive list
산출:
Id Name Type Size Created
1sV3_a1ySV0-jbLxhA8NIEts1KU_aWa-5 info.pdf bin 10.0 B 2018-08-27 20:26:20
1h-j3B5OLryp6HkeyTsd9PJaAtKK_GYyl 2018-12-ss-scalettapass dir 2018-08-27 20:26:19
awk
나는 성공 여부 에 관계없이 도구를 사용하여 이 출력을 구문 분석하려고 합니다 sed
.
문제는 크기 열의 빈 '필드'와 열의 동적 너비입니다.
이 출력을 구문 분석하는 방법을 아는 사람이 있습니까?
답변1
awk는 고정 너비 데이터를 처리할 수 있습니다. 먼저 열 너비를 결정해야 합니다.
fieldwidths=$(head -n 1 file | grep -Po '\S+\s*' | awk '{printf "%d ", length($0)}')
이 값은 "36 26 7 9 7 "
- 마지막 필드가 7자보다 큽니다. 임의로 70자로 만들어 보겠습니다.
fieldwidths=${fieldwidths/% /0}
이제 데이터를 읽고 이를 CSV로 변환해 보겠습니다.
awk -v FIELDWIDTHS="$fieldwidths" '{
for (i=1; i<=NF; i++) {
val = $i
sub(/ *$/, "", val)
gsub(/"/, "\"\"", val)
printf "%s\"%s\"", (i==1 ? "" : ","), val
}
print ""
}' file
출력:
"Id","Name","Type","Size","Created"
"1sV3_a1ySV0-jbLxhA8NIEts1KU_aWa-5","info.pdf","bin","10.0 B","2018-08-27 20:26:20"
"1h-j3B5OLryp6HkeyTsd9PJaAtKK_GYyl","2018-12-ss-scalettapass","dir","","2018-08-27 20:26:19"
Perl과 동일한 기능
perl -lne '
if ($. == 1) {
@head = ( /(\S+\s*)/g );
pop @head;
$patt = "^";
$patt .= "(.{" . length($_) . "})" for @head;
$patt .= "(.*)\$";
}
print join ",", map {s/"/""/g; s/\s+$//; qq("$_")} (/$patt/o);
' file
답변2
헤더(첫 번째 줄)를 검사하여 동적으로 압축 풀기 템플릿을 생성하는 함수를 Perl
사용하여 이를 수행할 수 있습니다 .unpack
perl -lpe '
$fmt //= join "", map("A" . length(), /\H+\h+(?=\H)/g), "A*";
$_ = join ",", map { s/"/""/gr =~ s/(.*)/"$1"/r } unpack $fmt;
' input-file.txt
설명:
-p
perl
줄 단위로 파일을 사용 하게 됩니다 . 레코드라고도 불리는 각 라인은$_
. 또 다른 효과는-p
다음 레코드를 가져오기 전에 현재 레코드를 자동 인쇄한다는 것입니다.-l
2가지 일을 하고, 세트를 합니다ORS = RS = \n
- 정규식은
/\H+\h+(?=\H)/g
마지막 필드를 제외한 모든 필드를 가져온 다음 에 공급합니다map
. map
이러한 필드의 길이를 계산하고 각 필드에 "A" 접두사를 붙입니다.- 위의 마지막 필드를 선택하지 않는 대신 포괄적인 "A*"를 추가합니다.
- 그런 다음
join
Null 구분 기호를 사용하여 문자열로 묶는 전달됩니다. 따라서 압축 해제 형식은 사용할 준비가 되었으며 함수//=
인 연산자 로 인해 다시 계산되지 않습니다defined-or
. - 이제 동적으로 생성된 언팩 포맷으로 무장하여 헤더를 포함한 모든 라인에 적용을 진행합니다.
unpack
제공된 형식을 사용하여 문자열(이 경우 현재 줄)의 압축을 풀고 압축이 풀린 필드를 내보냅니다.- 그런 다음 방출된 필드는
map
하나씩 입력되어{ ... }
코드에 설명된 단계를 수행합니다. 우리의 경우 각 필드에서 다음을 수행합니다. a) 큰따옴표를 두 배로 늘립니다. b) 필드를 큰따옴표로 묶습니다. - 필드 편집이 완료 되면
map
해당 필드를 으로 전달하고join
쉼표를 사용하여 결합하여,
멋진 작은CSV
파일을 만듭니다. - 추신:(ASCII의 경우 A) 형식 지정 문자를 사용할 때
unpack
에 의해 생성된 필드의 후행 공백을 잘라낼 필요가 없었습니다 .unpack
A
산출:
"Id","Name","Type","Size","Created"
"1sV3_a1ySV0-jbLxhA8NIEts1KU_aWa-5","info.pdf","bin","10.0 B","2018-08-27 20:26:20"
"1h-j3B5OLryp6HkeyTsd9PJaAtKK_GYyl","2018-12-ss-scalettapass","dir","","2018-08-27 20:26:19"
이 작업은 도구로 수행할 수 있지만 sed
2단계 접근 방식이 필요합니다. 먼저 입력의 헤더 라인을 사용하여 스크립트를 sed
동적으로 생성한 다음 입력 파일(헤더 포함)에 대해 작동하여 다음 작업을 수행합니다. 다음과 같이 원하는 작업을 수행합니다.
if="input-file.txt"
cmd=$(< "$if" head -n 1 | perl -lne 'print join $/, reverse map { $s += length();qq[s/./\\n/$s] } /\H+\h+(?=\H)/g')
sed -e '
'"${cmd}"'
s/"/""/g
s/[[:blank:]]*\n/","/g
s/.*/"&"/
' < "$if"