若要從多個格式相同的庫存表格收集同一個儲存格,請先將每個表格匯出為 CSV,再執行 Finder 捷徑讀取該位置的值並建立總覽。本指南會收集 B3、保留每個來源檔案的名稱,並避免覆寫現有結果。

建立捷徑前,先選擇正確的輸入資料

此工作流程適用於管理多個版面相同的庫存表格,並希望在另一份總覽中為每個表格建立一列的人。範例使用三個包含合成數量的臨時檔案。每個檔案代表一份匯出的表格;目標是第 3 列、第 B 欄,標題列也計入列數。

請區分三件事:試算表文件、文件中的表格,以及匯出的 CSV 檔案。Apple 的 Numbers 說明指出,CSV 可以匯出為每個表格各一個檔案,也可以合併表格。此處請選擇分別匯出檔案,因為合併表格可能會改變目標資料列的位置。在 Mac 上的 Numbers 中匯出為其他檔案格式。

下方的捷徑會將資料擷取工作交給一個小型 Python 程式。它不會把 Numbers 文件或 Excel 活頁簿當作純文字處理,也不會假設只要接受試算表檔案,某個動作就能存取其中的儲存格。Apple 說明了如何透過資訊面板查看動作接受的輸入和產生的輸出。檢查 Mac 上可用的動作時,請使用該面板。在 Mac 上的「捷徑」中瀏覽動作列表。

開始前,請參考這份判斷表:

起始狀況 此工作流程的準備方式
每份 Numbers 文件各有一個符合條件的表格 將每個表格匯出為 CSV。
一份文件中有多個符合條件的表格 分別匯出為 CSV 檔案,並確認要使用的表格。
已有以逗號分隔的 CSV 檔案 確認其編碼、版面和目標位置。
版面不同或庫存資料列位置會變動 先統一臨時範例的版面;單靠固定座標無法判斷哪個數量才是目標。

在此範例中,每個來源檔案的 A3 都必須是 Counted units,而 B3 則必須包含所需的值。檢查相鄰的標籤也能提供實用的診斷資訊:如果資料列位移,程式就會停止,而不是悄悄收集到不相關的值。這無法偵測所有可能的版面錯誤,因此準備輸入資料時,請確認這兩個儲存格。

準備臨時庫存檔案

此範例需要另外安裝 Python 3。使用 Python 網站提供的標準安裝程式時,可執行檔連結會放在 /usr/local/bin/。以下命令明確使用 /usr/local/bin/python3,不必依賴捷徑的命令搜尋路徑。請按照適用於你所用 Python 版本的安裝說明完成安裝,然後確認此命令可正常執行。在 macOS 上使用 Python。

/usr/local/bin/python3 --version

如果沒有這個路徑,請先完成 Python 安裝再繼續。此程式只使用 Python 標準函式庫,不需要安裝其他套件。Apple 的「終端機」使用手冊說明,可以使用可執行檔的完整路徑名稱,後接其引數來執行命令。在 Mac 上的「終端機」中執行命令和工具。

若要建立合成輸入資料,請將下方完整命令貼到「終端機」。命令會在桌面建立 Inventory Demo,如果該資料夾已存在,就會停止。請使用新的臨時資料夾,不要將這些範例合併到現有目錄中。

/usr/local/bin/python3 - <<'PY'
import csv
from pathlib import Path

root = Path.home() / "Desktop" / "Inventory Demo"
root.mkdir()
examples = [
    ("Birch", "A", "12"),
    ("Cedar", "B", "7"),
    ("Maple", "C", "0"),
]
for name, bin_name, count in examples:
    with (root / f"{name}.csv").open(
        "x", encoding="utf-8", newline=""
    ) as handle:
        csv.writer(handle).writerows([
            ["Item", "Value"],
            ["Bin", bin_name],
            ["Counted units", count],
        ])
print(root)
PY

若要另外測試 Numbers 匯出步驟,請在 Numbers 中開啟一個臨時 CSV,並透過 檔案 > 輸出至 > CSV 將它匯出到另一個臨時資料夾。每個表格請選擇一個檔案,關閉「包含表格名稱」,並使用 UTF-8 編碼。檢查匯出的表格,確認 A3 和 B3 仍包含預期的標籤和值。Apple 說明了這些匯出選項。Numbers 匯出設定。

請勿只將試算表的副檔名改成 .csv,以此代替匯出。此程式需要的是真正以逗號分隔的文字。接下來的操作示範中,請將三個原始合成 CSV 檔案放在一起。

建立用來產生總覽的程式

使用純文字編輯器,將下方完整程式儲存為 overview.py,放在 Inventory Demo 資料夾中。確認檔名以 .py 結尾,而不是 .py.txt。程式會將來源檔案路徑作為引數,讀取 B3,並在這些檔案所在的共同資料夾中建立 overview.csv。

import csv
import io
import sys
from pathlib import Path

ROW, COLUMN = 2, 1  # Zero-based: B3
LABEL = "Counted units"

def build_overview(arguments):
    if not arguments:
        raise ValueError("Select at least one source CSV.")
    paths = [Path(name).expanduser().resolve(strict=True)
             for name in arguments]
    if len(set(paths)) != len(paths):
        raise ValueError("The same source was supplied twice.")
    if len({path.parent for path in paths}) != 1:
        raise ValueError("Keep all source CSVs in one folder.")
    rows = []
    for path in sorted(paths, key=lambda p: p.name):
        if (not path.is_file() or path.suffix.lower() != ".csv"
                or path.name.casefold() == "overview.csv"):
            raise ValueError(f"Not a source CSV: {path.name}")
        with path.open(encoding="utf-8-sig", newline="") as handle:
            records = list(csv.reader(handle, strict=True))
        if len(records) <= ROW or len(records[ROW]) <= COLUMN:
            raise ValueError(f"{path.name}: B3 does not exist.")
        if records[ROW][0] != LABEL:
            raise ValueError(f"{path.name}: A3 must be {LABEL!r}.")
        value = records[ROW][COLUMN]
        status = "blank" if value.strip() == "" else "present"
        rows.append([path.name, "B3", value, status])
    buffer = io.StringIO(newline="")
    writer = csv.writer(buffer)
    writer.writerow(["Source file", "Cell", "Value", "Status"])
    writer.writerows(rows)
    return paths[0].parent / "overview.csv", buffer.getvalue()

def main(arguments):
    try:
        destination, content = build_overview(arguments)
        with destination.open("x", encoding="utf-8", newline="") as handle:
            handle.write(content)
    except (OSError, ValueError, csv.Error) as error:
        print(f"Stopped: {error}", file=sys.stderr)
        return 1
    print(f"Created: {destination}")
    return 0

if __name__ == "__main__":
    sys.exit(main(sys.argv[1:]))

此程式使用 CSV 剖析器,而不是依照逗號或換行符號拆分文字。Python 的 reader 會將欄位讀取為字串,文件也指定應以 newline="" 開啟 CSV 檔案。這樣便能處理包含逗號或內嵌換行符號的引號欄位。程式會保留擷取出的值,不會加總或轉換成數字。CSV 檔案的讀取與寫入。

程式刻意設下幾項限制,讓結果更容易檢查。每個輸入檔案都必須存在,所有解析後的來源路徑都必須位於同一資料夾,而且不接受重複的解析路徑。程式會依檔名排序,不會依賴 Finder 的選取順序。它也會拒絕名為 overview.csv 的輸入檔案,避免意外將先前的結果納入其中。

程式會先讀取並檢查所有來源,再開始建立輸出。如果缺少 B3,或 A3 中的標籤不符預期,程式就會停止。B3 存在但內容為空時,程式會建立標示為 blank 的資料列;值為 0 時,則會保留為 0,並標示為 present。因此,儲存格不存在、內容為空和數量為零,會有不同的結果。

輸出使用獨佔建立模式 \"x\"。Python 說明,此模式在目的地已存在時會失敗。因此,程式不會取代先前的總覽,也不會自行建立帶編號的檔名。實際寫入時若發生錯誤,仍可能留下不完整的新檔案;重試前,請檢查任何因寫入錯誤而留下的檔案。Python 的檔案開啟模式。

將程式連接到 Finder 捷徑

在「捷徑」中建立一個名為 Inventory Overview 的捷徑。打開 詳細資訊,啟用 作為快速動作使用,並選擇 Finder。在輸入項目設定中,保留 檔案 的啟用狀態,並關閉無關的內容類型。Apple 說明了接受檔案或資料夾輸入的捷徑可在 Finder 中使用,也說明了限制可接受輸入的控制項。在 Mac 上工作時執行捷徑,限制捷徑的輸入。

將無輸入時的行為設為 停止並回覆,並輸入例如 請在 Finder 中選取來源 CSV 檔案。 這樣可避免空白選取造成結果不明確。Apple 的輸入設定指南說明了這個選項及其回覆欄位。選擇缺少輸入時的回應方式。

加入「執行 Shell 腳本」。將 Shell 設為 /bin/zsh,將 Input 連接到 Shortcut Input,並將 Pass Input 設為 as arguments。用以下完整命令取代範例指令碼:

/usr/local/bin/python3 "$HOME/Desktop/Inventory Demo/overview.py" "$@"

請保留引號。加上引號的 \"$@\" 會將傳入的引數分開傳遞,保留包含空格的檔名。基於相同原因,指令碼路徑也加上了引號。zsh 手冊說明了位置參數和加上引號的陣列元素如何分開展開;Apple 的「終端機」使用手冊也說明了路徑名稱的引號用法。參數,在「終端機」中指定檔案和資料夾。

如果「捷徑」要求啟用指令碼功能,請選擇 捷徑 > 設定 > 進階,並勾選 允許執行指令碼。Apple 在允許從捷徑執行指令碼的說明中介紹了這項設定。「捷徑」進階設定。

設定完成後,流程如下:選取的檔案物件進入捷徑,其路徑會成為 Shell 引數,而 Python 會讀取這些檔案並寫入總覽。Shell 動作成功時會傳回文字結果,內容為包含目的地路徑名稱的 Created: 訊息。該訊息本身並不是 CSV 檔案。程式已建立檔案,因此不需要再加上儲存動作。

在 Finder 中,只選取 Birch.csv、Cedar.csv 和 Maple.csv。按住 Control 鍵並按一下選取項目,然後選擇 快速動作 > Inventory Overview。如果找不到捷徑,請使用 更多 > 自訂 檢查已啟用的 Finder 延伸功能,然後再次確認它接受的輸入類型。Apple 說明了如何自訂 Finder 快速動作,以及如何將捷徑加入該選單。在 Mac 上的 Finder 中執行快速動作。

檢查結果並處理重複執行

在 Numbers 中開啟示範資料夾中的 overview.csv。使用提供的合成檔案時,內容應如下:

Source file,Cell,Value,Status
Birch.csv,B3,12,present
Cedar.csv,B3,7,present
Maple.csv,B3,0,present

確認每個選取的來源檔案都各有一列輸出資料,且檔名能識別出正確的表格。範例中的值僅供說明,並非實際測量的庫存結果。程式只會回報值是否存在,不會檢查該值是否為有效數量。

若結果不符預期,請依序進行以下診斷:

  1. **Finder 中沒有捷徑:**檢查捷徑的 Finder 設定、接受的 檔案 輸入,以及已啟用的延伸功能。
  2. **找不到可執行檔或指令碼:**確認 Python 路徑正確,且 overview.py 仍位於指定的示範資料夾中。
  3. **缺少 B3 或 A3 錯誤:**在修改程式前,先檢查來源檔案匯出的資料列和匯出選項。
  4. **出現預期外的空白:**檢查 B3;程式會刻意保留空值。
  5. **目的地已存在:**將先前的臨時總覽重新命名,或移到來源資料夾之外,再重新執行。

你也可以從「終端機」呼叫相同的捷徑,檢查輸入路徑。Apple 說明了如何使用 -i 傳遞檔案輸入;透過管線傳送路徑名稱則會傳遞文字。請使用下方指定的檔案,不加上輸出旗標,因為輸出由 Python 程式負責建立。相同的檔名衝突規則仍然適用。從命令列執行捷徑。

shortcuts run "Inventory Overview" -i \
  "$HOME/Desktop/Inventory Demo/Birch.csv" \
  "$HOME/Desktop/Inventory Demo/Cedar.csv" \
  "$HOME/Desktop/Inventory Demo/Maple.csv"

每次建立的新總覽都會反映該次所選的 CSV 檔案。試算表有所變更時,必須重新匯出並再次執行。保留來源檔名、檢查相鄰標籤,以及區分空白值和零,可讓你在下一次庫存盤點前更容易確認這份小型總覽。

來源