운전사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
그런 다음 널 구분 기호를 사용하는 문자열 에 전달하여 하나의 문자열로 묶습니다. 따라서 압축이 풀린 형식은 이미 사용 가능하며//=
연산자가defined-or
함수 이므로 다시 평가되지 않습니다 .- 이제 동적으로 생성된 압축 풀기 형식을 사용하여 헤더를 포함한 모든 행에 적용을 진행합니다.
unpack
제공된 형식을 사용하여 문자열(이 경우 현재 줄)의 압축을 풀고 압축이 풀린 필드를 내보냅니다.- 그런 다음 방출된 필드를
map
여기에 입력하여 각 필드를 하나씩 작업하고{ ... }
코드에 설명된 단계를 수행합니다. 우리의 경우 각 필드에서 다음을 수행합니다. a) 큰따옴표. b) 필드를 큰따옴표로 묶습니다. - 필드를 편집한 후
map
해당 필드를 입력join
하고 쉼표를 사용하여 연결하여,
멋진 작은 파일을 만듭니다CSV
. - 첨부된:
unpack
(ASCII의 경우 A) 형식 문자를 사용할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"