description
Google Workspace CLI(gws)를 활용한 구글 시트/슬라이드 연동
Google Workspace CLI (gws)
구글 시트·슬라이드 데이터를 터미널에서 읽고 쓸 수 있다.
⚠️ +read/+append는 영문 시트명 에서만 안정적. 한국어·공백 포함 시트명은 Raw API 사용.
# 읽기 — 영문 시트명일 때
gws sheets +read --spreadsheet < 시트ID> --range ' Sheet1!A1:D10'
# 행 추가 (단일)
gws sheets +append --spreadsheet < 시트ID> --values ' Alice,100,true'
# 행 추가 (다중)
gws sheets +append --spreadsheet < 시트ID> --json-values ' [["a","b"],["c","d"]]'
⚠️ --params 인라인 JSON + ! 문자 = 파싱 에러
zsh에서 !(시트 범위 구분자)가 히스토리 확장으로 해석되어, 큰따옴표·작은따옴표 어느 쪽이든 인라인으로 넣으면 Invalid --params JSON 에러 발생.
→ 해결: 임시 파일 + $(cat) 패턴을 기본으로 사용
# ✅ 권장 패턴 — 임시 파일 경유 (모든 시트명에서 안정적)
cat > /tmp/gws_params.json << 'JSONEOF '
{"spreadsheetId": "<시트ID>", "range": "시트명!A1:Z100"}
JSONEOF
gws sheets spreadsheets values get --params " $( cat /tmp/gws_params.json) "
# ✅ 값 쓰기 — --json도 대량 데이터면 파일 경유 권장
cat > /tmp/gws_data.json << 'JSONEOF '
{"values": [["A1값", "B1값"], ["A2값", "B2값"]]}
JSONEOF
cat > /tmp/gws_params.json << 'JSONEOF '
{"spreadsheetId": "<시트ID>", "range": "시트명!A1:B2", "valueInputOption": "USER_ENTERED"}
JSONEOF
gws sheets spreadsheets values update \
--json " $( cat /tmp/gws_data.json) " \
--params " $( cat /tmp/gws_params.json) "
# ❌ 인라인 --params는 `!` 문자 때문에 불안정 — 사용 금지
# gws sheets ... --params '{"range": "Sheet1!A1:Z5"}'
# gws sheets ... --params "{\"range\": \"Sheet1!A1:Z5\"}"
# ✅ `!` 없는 params는 인라인 OK (batchUpdate, get 등)
gws sheets spreadsheets batchUpdate \
--json ' {"requests": [{"addSheet": {"properties": {"title": "시트명"}}}]}' \
--params ' {"spreadsheetId": "<시트ID>"}'
# 시트 목록 조회 (! 없으므로 인라인 OK)
gws sheets spreadsheets get \
--params ' {"spreadsheetId": "<시트ID>", "fields": "sheets.properties.title,sheets.properties.sheetId"}'
spreadsheets create로 제목 + 시트 구조를 한번에 생성 가능.
gws sheets spreadsheets create --json ' {
"properties": {"title": "스프레드시트 제목"},
"sheets": [
{"properties": {"title": "시트1"}},
{"properties": {"title": "시트2"}}
]
}'
# → 응답에서 spreadsheetId, spreadsheetUrl 확인
# 시트에 달린 코멘트 전체 조회
gws drive comments list \
--params ' {"fileId": "<시트ID>", "fields": "comments(content,author,createdTime,resolved,anchor)"}'
gws slides presentations 으로 슬라이드 생성·수정.
Slides API는 EMU(English Metric Unit) 사용. 자주 쓰는 값:
단위
EMU
1 inch
914,400
1 pt
12,700
슬라이드 너비 (10")
9,144,000
슬라이드 높이 (5.625")
5,143,500
# 1. 프레젠테이션 생성
gws slides presentations create --json ' {"title": "제목"}'
# → 응답에서 presentationId 확인
# 2. batchUpdate로 슬라이드 추가 + 콘텐츠 + 서식 일괄 적용
gws slides presentations batchUpdate \
--json " $( cat /tmp/slides_batch.json) " \
--params ' {"presentationId": "<프레젠테이션ID>"}'
슬라이드 batchUpdate는 수백 개 요청이 일반적 (7장 슬라이드 = ~466 requests).
수작업 JSON은 비현실적 → Python 스크립트로 JSON 생성 후 $(cat) 패턴 사용 .
# /tmp/gen_slides.py — 주요 헬퍼 패턴
EMU = 914400 ; PT = 12700
def text_box (page_id , obj_id , x , y , w , h ):
return {"createShape" : {"objectId" : obj_id , "shapeType" : "TEXT_BOX" ,
"elementProperties" : {"pageObjectId" : page_id ,
"size" : {"width" : {"magnitude" : w , "unit" : "EMU" }, "height" : {"magnitude" : h , "unit" : "EMU" }},
"transform" : {"scaleX" : 1 , "scaleY" : 1 , "translateX" : x , "translateY" : y , "unit" : "EMU" }}}}
# 생성 후: python3 /tmp/gen_slides.py > /tmp/slides_batch.json
createSlide — 슬라이드 추가 (objectId 지정 가능)
createShape — 텍스트박스, 사각형, 원 등
createLine — 직선, 화살표
createTable — 테이블 (행×열)
insertText — 텍스트 삽입 (테이블 셀은 cellLocation 사용)
updateTextStyle — 폰트, 크기, 색상, 볼드 등
updateParagraphStyle — 정렬
updateShapeProperties — 배경색, 아웃라인
updateTableCellProperties — 셀 배경색
updateLineProperties — 선 색상, 두께
updatePageProperties — 슬라이드 배경색
deleteObject — 슬라이드/요소 삭제
batchUpdate 원자성 : 요청 하나라도 실패하면 전체 롤백 — 디버깅 시 에러 메시지의 requests[N] 인덱스 확인
빈 텍스트 셀 트랩 : 테이블 셀에 "" insert 후 updateTextStyle → "has no text" 에러. 최소 공백 1자(" ") 필요
objectId 규칙 : 영숫자 + _ 만 허용, 프레젠테이션 내 유니크해야 함
텍스트 범위 : updateTextStyle에서 부분 스타일링 시 textRange: {type: "FIXED_RANGE", startIndex, endIndex} 사용
! 문자 (range 구분자) : --params 인라인에 시트명!A1 패턴 넣으면 zsh 히스토리 확장 충돌로 JSON 파싱 에러. 임시 파일 + $(cat) 패턴 필수
한국어·공백 시트명 : +read/+append 헬퍼 사용 불가 → Raw API 사용
대량 데이터 : JSON 이스케이프/셸 인자 제한 → cat > /tmp/file.json << 'EOF' 후 --json "$(cat /tmp/file.json)" 활용
시트 서식(색상, 병합, 테두리): batchUpdate + repeatCell/mergeCells/updateBorders 사용
token_cache.json이 암호화된 바이너리인데 JSON으로 읽히면서 토큰
복호화 실패 → 모든 API 호출에서 403 발생.
rm ~/.config/gws/token_cache.json
캐시 삭제 후 정상 동작. gws auth login 재인증으로는 해결 안 됨
(캐시가 덮어써지지 않음).