[Golang]呼叫外部shell程式處理檔案

z_paul發表於2021-09-09

在需要對檔案進行操作的一些場景,比如檔案合併,計算檔案hash或大小,除了可以完全使用golang來處理,也可以藉助外部shell或bash來完成。shell是應用程式和linux核心之間的介面程式,而bash可簡單理解為shell的加強版,支援更多的命令;透過bash來完成運維相關的工作是比較常見的場景,設計到檔案的處理更是常態。
因此大多數情況下,golang呼叫外部shell來處理檔案也是合理的做法。以下是一個簡單的例子,提供幾個工具方法:計算檔案sha1、大小、合併檔案等。詳細參考程式碼如下所示:

// @Title  檔案工具方法
// @Description  檔案操作相關工具方法
// @Author xiaomo
// @Update  2020/04/01
package util

import (
	"fmt"
	"os/exec"
	"strconv"
	"strings"
	"regexp"
)

// 以下合併操作適用於linux平臺

const (
	// 透過shell合併分塊檔案
	MERGE_FILE_CMD = `
	#!/bin/bash
	# 需要進行合併的分片所在的目錄
	chunkDir=$1
	# 合併後的檔案的完成路徑(目錄+檔名)
	mergePath=$2
	
	echo "分塊合併,輸入目錄: " $chunkDir
	
	if [ ! -f $mergePath ]; then
			echo "$mergePath not exist"
	else
			rm -f $mergePath
	fi
	
	for chunk in $(ls $chunkDir | sort -n)
	do
			cat $chunkDir/${chunk} >> ${mergePath}
	done
	
	echo "合併完成,輸出:" mergePath
	`

	// 計算檔案sha1值
	FILE_SHA1SUM_CMD = `
	#!/bin/bash
	sha1sum $1 | awk '{print $1}'
	`

	// 計算檔案大小
	FILE_SIZE_CMD = `
	#!/bin/bash
	ls -l $1 | awk '{print $5}'
	`
)

// ComputeFileSizeByShell: 透過呼叫shell來計算檔案大小
// @return  (string, error): (檔案hash, 錯誤資訊)
func ComputeFileSizeByShell(destPath string) (int, error) {
	cmdStr := strings.Replace(FILE_SIZE_CMD, "$1", destPath, 1)
	fSizeCmd := exec.Command("bash", "-c", cmdStr)
	if fSizeStr, err := fSizeCmd.Output(); err != nil {
		fmt.Println(err)
		return -1, err
	}  else {
		reg := regexp.MustCompile("\s+")
		fSize, err := strconv.Atoi(reg.ReplaceAllString(string(fSizeStr), ""))
		if err != nil {
			fmt.Println(err)
			return -1, err
		}
		return fSize, nil
	}
}

// ComputeSha1ByShell: 透過呼叫shell來計算檔案sha1
// @return  (string, error): (檔案hash, 錯誤資訊)
func ComputeSha1ByShell(destPath string) (string, error) {
	cmdStr := strings.Replace(FILE_SHA1SUM_CMD, "$1", destPath, 1)
	hashCmd := exec.Command("bash", "-c", cmdStr)
	if filehash, err := hashCmd.Output(); err != nil {
		fmt.Println(err)
		return "", err
	}  else {
		reg := regexp.MustCompile("\s+")
		return reg.ReplaceAllString(string(filehash), ""), nil
	}
}

// MergeChuncksByShell: 透過呼叫shell來合併檔案分塊,分塊檔名須有序 (如分塊名分別為: 1, 2, 3, ...)
// @return bool: 合併成功將返回true, 否則返回false
func MergeChuncksByShell(chunkDir string, destPath string, fileSha1 string) bool {
	// 合併分塊
	cmdStr := strings.Replace(MERGE_FILE_CMD, "$1", chunkDir, 1)
	cmdStr = strings.Replace(cmdStr, "$2", destPath, 1)
	mergeCmd := exec.Command("bash", "-c", cmdStr)
	if _, err := mergeCmd.Output(); err != nil {
		fmt.Println(err)
		return false
	} 

	// 計算合併後的檔案hash
	if filehash, err := ComputeSha1ByShell(destPath); err != nil {
		fmt.Println(err)
		return false
	}  else	if string(filehash) != fileSha1 { // 判斷檔案hash是否符合給定值
		return false
	} else {
		fmt.Println("check sha1: "+destPath+ " " + filehash+" " + fileSha1)
	}
	
	return true
}

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/75/viewspace-2825154/,如需轉載,請註明出處,否則將追究法律責任。

相關文章