Initial commit
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
/.config.ini
|
||||
/*.jar
|
||||
@@ -0,0 +1,195 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
: <<'DOC'
|
||||
ask — AI terminal assistant (macOS)
|
||||
|
||||
Setup API key (Keychain):
|
||||
security add-generic-password -a "$USER" -s TK_AI_API_TOKEN -w "YOUR_API_KEY"
|
||||
|
||||
Usage:
|
||||
ask "question"
|
||||
ask -i # interactive mode
|
||||
ask -v # verbose (debug raw response)
|
||||
DOC
|
||||
|
||||
# ===== CONFIG =====
|
||||
SERVER="https://ai.acbpro.com/v1/chat/completions"
|
||||
MODEL="gpt-5.3-codex"
|
||||
KEY_NAME="TK_AI_API_TOKEN"
|
||||
|
||||
VERBOSE=0
|
||||
INTERACTIVE=0
|
||||
|
||||
# ===== COLORS =====
|
||||
GREEN="\033[1;32m"
|
||||
CYAN="\033[1;36m"
|
||||
YELLOW="\033[1;33m"
|
||||
RED="\033[1;31m"
|
||||
RESET="\033[0m"
|
||||
|
||||
# ===== PARSE FLAGS =====
|
||||
while [[ "$1" == -* ]]; do
|
||||
case "$1" in
|
||||
-v) VERBOSE=1 ;;
|
||||
-i) INTERACTIVE=1 ;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
# ===== LOAD TOKEN =====
|
||||
API_TOKEN=$(security find-generic-password -a "$USER" -s "$KEY_NAME" -w 2>/dev/null | tr -d '\n')
|
||||
|
||||
if [ -z "$API_TOKEN" ]; then
|
||||
echo "❌ API token not found in Keychain ($KEY_NAME)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ===== SYSTEM PROMPT =====
|
||||
SYSTEM_PROMPT="You are a terminal assistant for macOS (zsh/bash).
|
||||
|
||||
- Default: return ONLY the command, no explanation.
|
||||
- If user asks for explanation, then explain.
|
||||
- Commands must be safe and runnable.
|
||||
- Prefer standard macOS/Linux tools.
|
||||
- No markdown, no code block.
|
||||
"
|
||||
|
||||
# ===== TERMINAL STATUS =====
|
||||
supports_status_line() {
|
||||
[ -t 2 ] && [ "${TERM:-}" != "dumb" ]
|
||||
}
|
||||
|
||||
render_status_line() {
|
||||
supports_status_line || return 0
|
||||
printf '\r\033[2K%b' "$1" >&2
|
||||
}
|
||||
|
||||
clear_status_line() {
|
||||
supports_status_line || return 0
|
||||
printf '\r\033[2K' >&2
|
||||
}
|
||||
|
||||
print_response() {
|
||||
if [ -t 1 ] && [ "${TERM:-}" != "dumb" ]; then
|
||||
echo -e "${CYAN}🤖 $1${RESET}"
|
||||
else
|
||||
printf '%s\n' "$1"
|
||||
fi
|
||||
}
|
||||
|
||||
# ===== FUNCTION CALL API =====
|
||||
call_api() {
|
||||
local Q="$1"
|
||||
local CWD GIT_BRANCH LAST_CMD JSON
|
||||
local START_TIME TMP_FILE CURL_PID
|
||||
local SPINNER i NOW ELAPSED CHAR COLOR
|
||||
local RESPONSE CONTENT CURL_STATUS
|
||||
|
||||
CWD="$(pwd)"
|
||||
GIT_BRANCH="$(git branch --show-current 2>/dev/null)"
|
||||
LAST_CMD="$(fc -ln -1 2>/dev/null)"
|
||||
|
||||
JSON=$(jq -n \
|
||||
--arg model "$MODEL" \
|
||||
--arg sys "$SYSTEM_PROMPT" \
|
||||
--arg q "$Q" \
|
||||
--arg cwd "$CWD" \
|
||||
--arg branch "$GIT_BRANCH" \
|
||||
--arg last "$LAST_CMD" \
|
||||
'{
|
||||
model: $model,
|
||||
messages: [
|
||||
{role: "system", content: $sys},
|
||||
{role: "user", content:
|
||||
("Context:
|
||||
" +
|
||||
"cwd: " + $cwd + "
|
||||
" +
|
||||
"git_branch: " + $branch + "
|
||||
" +
|
||||
"last_command: " + $last + "
|
||||
|
||||
" +
|
||||
"Request:
|
||||
" + $q)
|
||||
}
|
||||
]
|
||||
}'
|
||||
)
|
||||
|
||||
# ===== CALL (async) =====
|
||||
START_TIME=$(date +%s)
|
||||
TMP_FILE=$(mktemp)
|
||||
|
||||
curl -s "$SERVER" \
|
||||
-H "Authorization: Bearer $API_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$JSON" > "$TMP_FILE" &
|
||||
|
||||
CURL_PID=$!
|
||||
trap 'clear_status_line; [ -n "${CURL_PID:-}" ] && kill "${CURL_PID}" 2>/dev/null; [ -n "${TMP_FILE:-}" ] && rm -f "${TMP_FILE}"; exit 130' INT TERM
|
||||
|
||||
# ===== SPINNER + TIMER =====
|
||||
SPINNER='|/-\'
|
||||
i=0
|
||||
if supports_status_line; then
|
||||
while kill -0 "$CURL_PID" 2>/dev/null; do
|
||||
NOW=$(date +%s)
|
||||
ELAPSED=$((NOW - START_TIME))
|
||||
|
||||
CHAR=${SPINNER:i%${#SPINNER}:1}
|
||||
|
||||
if [ "$ELAPSED" -lt 10 ]; then COLOR="$GREEN";
|
||||
elif [ "$ELAPSED" -lt 30 ]; then COLOR="$YELLOW";
|
||||
else COLOR="$RED"; fi
|
||||
|
||||
render_status_line "${COLOR}⏳ calling ${CHAR} ${ELAPSED}s${RESET}"
|
||||
|
||||
i=$((i+1))
|
||||
sleep 0.1
|
||||
done
|
||||
fi
|
||||
|
||||
wait "$CURL_PID"
|
||||
CURL_STATUS=$?
|
||||
clear_status_line
|
||||
trap - INT TERM
|
||||
|
||||
RESPONSE=$(<"$TMP_FILE")
|
||||
rm -f "$TMP_FILE"
|
||||
|
||||
if [ "$CURL_STATUS" -ne 0 ]; then
|
||||
echo "❌ request failed (curl exit $CURL_STATUS)" >&2
|
||||
[ -n "$RESPONSE" ] && echo "$RESPONSE" >&2
|
||||
return "$CURL_STATUS"
|
||||
fi
|
||||
|
||||
if [ "$VERBOSE" -eq 1 ]; then
|
||||
echo -e "${YELLOW}🔧 RAW RESPONSE:${RESET}" >&2
|
||||
echo "$RESPONSE" >&2
|
||||
fi
|
||||
|
||||
CONTENT=$(echo "$RESPONSE" | jq -r '.choices[0].message.content // .response // .text // .')
|
||||
|
||||
print_response "$CONTENT"
|
||||
}
|
||||
|
||||
# ===== INTERACTIVE MODE =====
|
||||
if [ "$INTERACTIVE" -eq 1 ]; then
|
||||
echo -e "${GREEN}💬 Interactive mode (Ctrl+C để thoát)${RESET}"
|
||||
while true; do
|
||||
printf "${GREEN}❓ ask> ${RESET}"
|
||||
read Q
|
||||
[ -z "$Q" ] && continue
|
||||
call_api "$Q"
|
||||
done
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# ===== NORMAL MODE =====
|
||||
if [ $# -eq 0 ]; then
|
||||
echo "Usage: ask [-v] [-i] <question>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
call_api "$*"
|
||||
Executable
+859
@@ -0,0 +1,859 @@
|
||||
#!/bin/bash
|
||||
# cleanup.sh
|
||||
# Script dọn dẹp các ứng dụng nặng và các bản cũ trên macOS
|
||||
# Sử dụng: bash cleanup.sh
|
||||
|
||||
# -----------------------------
|
||||
# Function: cleanup chung cho thư mục chứa version
|
||||
# $1 = label (vd: "Edge", "Edge Updater")
|
||||
# $2 = đường dẫn thư mục
|
||||
# -----------------------------
|
||||
cleanup_versions() {
|
||||
local label="$1"
|
||||
local target_dir="$2"
|
||||
|
||||
echo "--- [$label] ---"
|
||||
echo " $target_dir"
|
||||
|
||||
if [ ! -d "$target_dir" ]; then
|
||||
echo " ⚠ Thư mục không tồn tại."
|
||||
return
|
||||
fi
|
||||
|
||||
pushd "$target_dir" > /dev/null || return
|
||||
|
||||
# Lấy các thư mục version dạng x.y.z.w và sort theo version số.
|
||||
local raw_dirs=()
|
||||
local d
|
||||
shopt -s nullglob
|
||||
for d in [0-9]*.[0-9]*.[0-9]*.[0-9]*; do
|
||||
[[ -d "$d" ]] && raw_dirs+=("$d")
|
||||
done
|
||||
shopt -u nullglob
|
||||
|
||||
if [ ${#raw_dirs[@]} -eq 0 ]; then
|
||||
echo " ⚠ Thư mục rỗng, không có phiên bản nào."
|
||||
popd > /dev/null
|
||||
return
|
||||
fi
|
||||
|
||||
local dirs=()
|
||||
while IFS= read -r d; do
|
||||
[[ -n "$d" ]] && dirs+=("$d")
|
||||
done < <(
|
||||
printf '%s\n' "${raw_dirs[@]}" |
|
||||
awk -F'.' '{ printf "%05d.%05d.%05d.%05d\t%s\n", $1, $2, $3, $4, $0 }' |
|
||||
sort |
|
||||
cut -f2-
|
||||
)
|
||||
|
||||
local last_index=$(( ${#dirs[@]} - 1 ))
|
||||
local keep="${dirs[$last_index]}"
|
||||
|
||||
# Helper: lấy size thư mục
|
||||
dir_size() { du -sh "$1" 2>/dev/null | cut -f1 | xargs; }
|
||||
|
||||
if [ ${#dirs[@]} -le 1 ]; then
|
||||
echo " ✓ Phiên bản hiện tại: $keep ($(dir_size "$keep")) — không có bản cũ."
|
||||
popd > /dev/null
|
||||
return
|
||||
fi
|
||||
|
||||
echo " ✓ Giữ lại: $keep ($(dir_size "$keep"))"
|
||||
echo " ✗ Sẽ xóa:"
|
||||
local i
|
||||
for ((i = 0; i < ${#dirs[@]} - 1; i++)); do
|
||||
echo " - ${dirs[$i]} ($(dir_size "${dirs[$i]}"))"
|
||||
done
|
||||
|
||||
local confirm
|
||||
read -r -p " Xác nhận xóa? (Y/n): " confirm
|
||||
if [[ -n "$confirm" && ! "$confirm" =~ ^([yY]|[yY][eE][sS])$ ]]; then
|
||||
echo " Đã hủy."
|
||||
popd > /dev/null
|
||||
return
|
||||
fi
|
||||
|
||||
for ((i = 0; i < ${#dirs[@]} - 1; i++)); do
|
||||
echo " Đã xóa: ${dirs[$i]}"
|
||||
rm -rf -- "${dirs[$i]}"
|
||||
done
|
||||
|
||||
popd > /dev/null
|
||||
}
|
||||
|
||||
# -----------------------------
|
||||
# Function: Cleanup Go mod cache
|
||||
# -----------------------------
|
||||
cleanup_go() {
|
||||
echo "--- [Go Mod Cache] ---"
|
||||
if ! command -v go &> /dev/null; then
|
||||
echo " ⚠ go command not found."
|
||||
return
|
||||
fi
|
||||
|
||||
local GOMODCACHE
|
||||
GOMODCACHE=$(go env GOMODCACHE)
|
||||
|
||||
if [ -d "$GOMODCACHE" ]; then
|
||||
echo " $GOMODCACHE"
|
||||
local size
|
||||
size=$(du -sh "$GOMODCACHE" 2>/dev/null | cut -f1 | xargs)
|
||||
echo " ✗ Sẽ xóa bộ nhớ cache: $size"
|
||||
|
||||
local confirm
|
||||
read -r -p " Xác nhận xóa? (Y/n): " confirm
|
||||
if [[ -n "$confirm" && ! "$confirm" =~ ^([yY]|[yY][eE][sS])$ ]]; then
|
||||
echo " Đã hủy."
|
||||
return
|
||||
fi
|
||||
|
||||
go clean -modcache
|
||||
echo " Đã xong."
|
||||
else
|
||||
echo " ✓ Bộ nhớ cache rỗng hoặc không tồn tại."
|
||||
fi
|
||||
}
|
||||
|
||||
# -----------------------------
|
||||
# Function: Cleanup NPM cache
|
||||
# -----------------------------
|
||||
cleanup_npm() {
|
||||
echo "--- [NPM Cache] ---"
|
||||
if ! command -v npm &> /dev/null; then
|
||||
echo " ⚠ npm command not found."
|
||||
return
|
||||
fi
|
||||
|
||||
local NPM_CACHE
|
||||
NPM_CACHE=$(npm config get cache)
|
||||
|
||||
if [ -d "$NPM_CACHE" ]; then
|
||||
echo " $NPM_CACHE"
|
||||
local size
|
||||
# Lưu ý: npm cache size thực tế thường lớn hơn kết quả du vì cấu trúc thư mục phức tạp
|
||||
size=$(du -sh "$NPM_CACHE" 2>/dev/null | cut -f1 | xargs)
|
||||
echo " ✗ Sẽ xóa bộ nhớ cache: $size"
|
||||
|
||||
local confirm
|
||||
read -r -p " Xác nhận xóa? (Y/n): " confirm
|
||||
if [[ -n "$confirm" && ! "$confirm" =~ ^([yY]|[yY][eE][sS])$ ]]; then
|
||||
echo " Đã hủy."
|
||||
return
|
||||
fi
|
||||
|
||||
npm cache clean --force
|
||||
echo " Đã xong."
|
||||
else
|
||||
echo " ✓ Bộ nhớ cache rỗng hoặc không tồn tại."
|
||||
fi
|
||||
}
|
||||
|
||||
# -----------------------------
|
||||
# Function: Cleanup old VS Code extensions
|
||||
# Giữ lại phiên bản mới nhất của mỗi extension
|
||||
# -----------------------------
|
||||
cleanup_vscode_extensions() {
|
||||
echo "--- [VS Code Extensions] ---"
|
||||
local EXT_DIR="$HOME/.vscode/extensions"
|
||||
echo " $EXT_DIR"
|
||||
|
||||
if [ ! -d "$EXT_DIR" ]; then
|
||||
echo " ⚠ Thư mục không tồn tại."
|
||||
return
|
||||
fi
|
||||
|
||||
# Build "ext_id<TAB>dirname" pairs
|
||||
local entries=()
|
||||
local basename ext_id
|
||||
|
||||
shopt -s nullglob
|
||||
for dir in "$EXT_DIR"/*/; do
|
||||
basename=$(command basename "$dir")
|
||||
[[ "$basename" == .* ]] && continue
|
||||
# Extract extension ID: everything before -<version>
|
||||
ext_id=$(echo "$basename" | sed 's/-[0-9][0-9.]*.*$//')
|
||||
[ -z "$ext_id" ] && continue
|
||||
entries+=("${ext_id}"$'\t'"${basename}")
|
||||
done
|
||||
shopt -u nullglob
|
||||
|
||||
if [ ${#entries[@]} -eq 0 ]; then
|
||||
echo " ⚠ Không có extension nào."
|
||||
return
|
||||
fi
|
||||
|
||||
# Sort by ext_id (field 1), then by dirname (field 2) for version ordering
|
||||
local sorted
|
||||
sorted=$(printf '%s\n' "${entries[@]}" | sort -t$'\t' -k1,1 -k2,2)
|
||||
|
||||
# Group by ext_id, find old versions
|
||||
local to_delete=()
|
||||
local to_keep=()
|
||||
local group=()
|
||||
local prev_id=""
|
||||
|
||||
while IFS=$'\t' read -r ext_id dirname; do
|
||||
if [ -n "$prev_id" ] && [ "$ext_id" != "$prev_id" ]; then
|
||||
# Process previous group
|
||||
if [ ${#group[@]} -gt 1 ]; then
|
||||
local last=$(( ${#group[@]} - 1 ))
|
||||
to_keep+=("${group[$last]}")
|
||||
local g
|
||||
for ((g = 0; g < last; g++)); do
|
||||
to_delete+=("${group[$g]}")
|
||||
done
|
||||
fi
|
||||
group=()
|
||||
fi
|
||||
group+=("$dirname")
|
||||
prev_id="$ext_id"
|
||||
done <<< "$sorted"
|
||||
|
||||
# Process last group
|
||||
if [ ${#group[@]} -gt 1 ]; then
|
||||
local last=$(( ${#group[@]} - 1 ))
|
||||
to_keep+=("${group[$last]}")
|
||||
local g
|
||||
for ((g = 0; g < last; g++)); do
|
||||
to_delete+=("${group[$g]}")
|
||||
done
|
||||
fi
|
||||
|
||||
if [ ${#to_delete[@]} -eq 0 ]; then
|
||||
echo " ✓ Không có extension cũ để xóa."
|
||||
return
|
||||
fi
|
||||
|
||||
echo " ✓ Giữ lại (mới nhất):"
|
||||
local k
|
||||
for k in "${to_keep[@]}"; do
|
||||
local size
|
||||
size=$(du -sh "$EXT_DIR/$k" 2>/dev/null | cut -f1 | xargs)
|
||||
echo " + $k ($size)"
|
||||
done
|
||||
|
||||
echo " ✗ Sẽ xóa (cũ):"
|
||||
local d
|
||||
for d in "${to_delete[@]}"; do
|
||||
local size
|
||||
size=$(du -sh "$EXT_DIR/$d" 2>/dev/null | cut -f1 | xargs)
|
||||
echo " - $d ($size)"
|
||||
done
|
||||
|
||||
local confirm
|
||||
read -r -p " Xác nhận xóa? (Y/n): " confirm
|
||||
if [[ -n "$confirm" && ! "$confirm" =~ ^([yY]|[yY][eE][sS])$ ]]; then
|
||||
echo " Đã hủy."
|
||||
return
|
||||
fi
|
||||
|
||||
for d in "${to_delete[@]}"; do
|
||||
echo " Đã xóa: $d"
|
||||
rm -rf -- "$EXT_DIR/$d"
|
||||
done
|
||||
}
|
||||
|
||||
# -----------------------------
|
||||
# Function: Cleanup old Antigravity browser recordings
|
||||
# -----------------------------
|
||||
cleanup_agy_recordings() {
|
||||
local days="${1:-7}"
|
||||
local rec_dir="$HOME/.gemini/antigravity/browser_recordings"
|
||||
|
||||
echo "--- [Antigravity Recordings] ---"
|
||||
echo " $rec_dir"
|
||||
|
||||
if [ ! -d "$rec_dir" ]; then
|
||||
echo " ⚠ Thư mục không tồn tại."
|
||||
return
|
||||
fi
|
||||
|
||||
local to_delete=()
|
||||
local total_size=0
|
||||
local dir
|
||||
|
||||
shopt -s nullglob
|
||||
for dir in "$rec_dir"/*/; do
|
||||
[ -d "$dir" ] || continue
|
||||
local dirname
|
||||
dirname=$(basename "$dir")
|
||||
local size mod_date
|
||||
size=$(du -sh "$dir" 2>/dev/null | cut -f1 | xargs)
|
||||
mod_date=$(stat -f "%Sm" -t "%Y-%m-%d" "$dir")
|
||||
|
||||
if [ "$(find "$dir" -maxdepth 0 -mtime +"$days" 2>/dev/null)" ]; then
|
||||
echo " - $dirname ($size, $mod_date)"
|
||||
to_delete+=("$dir")
|
||||
total_size=$((total_size + $(du -sk "$dir" | cut -f1)))
|
||||
else
|
||||
echo " + $dirname ($size, $mod_date) [KEEP]"
|
||||
fi
|
||||
done
|
||||
shopt -u nullglob
|
||||
|
||||
if [ ${#to_delete[@]} -eq 0 ]; then
|
||||
echo " ✓ Không có recording cũ (>${days} ngày) để xóa."
|
||||
return
|
||||
fi
|
||||
|
||||
local total_human
|
||||
total_human=$(echo "scale=1; $total_size / 1024" | bc)
|
||||
echo " ✗ Sẽ xóa ${#to_delete[@]} recording(s), tổng: ${total_human} MiB"
|
||||
|
||||
local confirm
|
||||
read -r -p " Xác nhận xóa? (Y/n): " confirm
|
||||
if [[ -n "$confirm" && ! "$confirm" =~ ^([yY]|[yY][eE][sS])$ ]]; then
|
||||
echo " Đã hủy."
|
||||
return
|
||||
fi
|
||||
|
||||
for dir in "${to_delete[@]}"; do
|
||||
echo " Đã xóa: $(basename "$dir")"
|
||||
rm -rf -- "$dir"
|
||||
done
|
||||
}
|
||||
|
||||
# -----------------------------
|
||||
# Function: Cleanup Homebrew
|
||||
# -----------------------------
|
||||
cleanup_homebrew() {
|
||||
echo "--- [Homebrew] ---"
|
||||
if ! command -v brew &> /dev/null; then
|
||||
echo " ⚠ brew command not found."
|
||||
return
|
||||
fi
|
||||
|
||||
echo " Đang cập nhật Homebrew..."
|
||||
brew update --quiet
|
||||
|
||||
local outdated
|
||||
outdated=$(brew outdated 2>/dev/null)
|
||||
if [ -n "$outdated" ]; then
|
||||
echo " ✗ Các package cần upgrade:"
|
||||
echo "$outdated" | sed 's/^/ - /'
|
||||
local confirm
|
||||
read -r -p " Upgrade tất cả? (Y/n): " confirm
|
||||
if [[ -z "$confirm" || "$confirm" =~ ^([yY]|[yY][eE][sS])$ ]]; then
|
||||
brew upgrade --quiet
|
||||
echo " Đã upgrade xong."
|
||||
else
|
||||
echo " Bỏ qua upgrade."
|
||||
fi
|
||||
else
|
||||
echo " ✓ Tất cả package đã cập nhật."
|
||||
fi
|
||||
|
||||
# Cleanup cache
|
||||
local cache_size
|
||||
cache_size=$(brew --cache 2>/dev/null)
|
||||
if [ -d "$cache_size" ]; then
|
||||
local size
|
||||
size=$(du -sh "$cache_size" 2>/dev/null | cut -f1 | xargs)
|
||||
echo " ✗ Cache: $size ($cache_size)"
|
||||
fi
|
||||
|
||||
echo " Đang dọn dẹp cache và autoremove..."
|
||||
brew cleanup --prune=all -s 2>/dev/null
|
||||
brew autoremove 2>/dev/null
|
||||
echo " Đã xong."
|
||||
}
|
||||
|
||||
# -----------------------------
|
||||
# Function: Cleanup VS Code C++ Tools cache
|
||||
# -----------------------------
|
||||
cleanup_vscode_cpptools() {
|
||||
local cache_dir="$HOME/Library/Caches/vscode-cpptools"
|
||||
|
||||
echo "--- [VS Code C++ Tools Cache] ---"
|
||||
echo " $cache_dir"
|
||||
|
||||
if [ ! -d "$cache_dir" ]; then
|
||||
echo " ⚠ Thư mục không tồn tại."
|
||||
return
|
||||
fi
|
||||
|
||||
local total_size
|
||||
total_size=$(du -sh "$cache_dir" 2>/dev/null | cut -f1 | xargs)
|
||||
echo " Tổng dung lượng: $total_size"
|
||||
|
||||
# ipch (IntelliSense cache) - thường chiếm nhiều nhất
|
||||
if [ -d "$cache_dir/ipch" ]; then
|
||||
local ipch_size
|
||||
ipch_size=$(du -sh "$cache_dir/ipch" 2>/dev/null | cut -f1 | xargs)
|
||||
echo " - ipch (IntelliSense cache): $ipch_size"
|
||||
fi
|
||||
|
||||
# Các thư mục hash cache khác
|
||||
local hash_count=0
|
||||
local hash_size=0
|
||||
local d
|
||||
shopt -s nullglob
|
||||
for d in "$cache_dir"/*/; do
|
||||
local dirname
|
||||
dirname=$(basename "$d")
|
||||
[[ "$dirname" == "ipch" ]] && continue
|
||||
hash_count=$((hash_count + 1))
|
||||
hash_size=$((hash_size + $(du -sk "$d" | cut -f1)))
|
||||
done
|
||||
shopt -u nullglob
|
||||
|
||||
if [ $hash_count -gt 0 ]; then
|
||||
local hash_human
|
||||
hash_human=$(echo "scale=1; $hash_size / 1024" | bc)
|
||||
echo " - $hash_count thư mục cache khác: ${hash_human} MiB"
|
||||
fi
|
||||
|
||||
echo " ✗ Sẽ xóa toàn bộ cache"
|
||||
local confirm
|
||||
read -r -p " Xác nhận xóa? (Y/n): " confirm
|
||||
if [[ -n "$confirm" && ! "$confirm" =~ ^([yY]|[yY][eE][sS])$ ]]; then
|
||||
echo " Đã hủy."
|
||||
return
|
||||
fi
|
||||
|
||||
rm -rf -- "$cache_dir"/*
|
||||
echo " Đã xóa toàn bộ cache. VS Code sẽ tạo lại khi cần."
|
||||
}
|
||||
|
||||
# -----------------------------
|
||||
# Function: Cleanup IDE logs (JetBrains, Google, etc.)
|
||||
# Giữ lại phiên bản mới nhất của mỗi IDE
|
||||
# $1 = label, $2 = đường dẫn thư mục logs
|
||||
# -----------------------------
|
||||
cleanup_ide_logs() {
|
||||
local label="$1"
|
||||
local logs_dir="$2"
|
||||
|
||||
echo "--- [$label Logs] ---"
|
||||
echo " $logs_dir"
|
||||
|
||||
if [ ! -d "$logs_dir" ]; then
|
||||
echo " ⚠ Thư mục không tồn tại."
|
||||
return
|
||||
fi
|
||||
|
||||
local to_delete=()
|
||||
local all_dirs=()
|
||||
|
||||
shopt -s nullglob
|
||||
for d in "$logs_dir"/*/; do
|
||||
local dirname
|
||||
dirname=$(basename "$d")
|
||||
[[ "$dirname" == "Toolbox" || "$dirname" == ".DS_Store" ]] && continue
|
||||
all_dirs+=("$dirname")
|
||||
done
|
||||
shopt -u nullglob
|
||||
|
||||
if [ ${#all_dirs[@]} -eq 0 ]; then
|
||||
echo " ✓ Không có log nào."
|
||||
return
|
||||
fi
|
||||
|
||||
local sorted
|
||||
sorted=$(printf '%s\n' "${all_dirs[@]}" | sort)
|
||||
|
||||
local prev_ide=""
|
||||
local group=()
|
||||
|
||||
while IFS= read -r dirname; do
|
||||
[ -z "$dirname" ] && continue
|
||||
local ide_name
|
||||
ide_name=$(echo "$dirname" | sed 's/[0-9].*$//')
|
||||
[ -z "$ide_name" ] && continue
|
||||
|
||||
if [ -n "$prev_ide" ] && [ "$ide_name" != "$prev_ide" ]; then
|
||||
if [ ${#group[@]} -gt 0 ]; then
|
||||
local last_index=$(( ${#group[@]} - 1 ))
|
||||
local keep="${group[$last_index]}"
|
||||
local keep_size
|
||||
keep_size=$(du -sh "$logs_dir/$keep" 2>/dev/null | cut -f1 | xargs)
|
||||
echo " [$prev_ide]"
|
||||
echo " + $keep ($keep_size) [KEEP]"
|
||||
local i
|
||||
for ((i = 0; i < last_index; i++)); do
|
||||
local old="${group[$i]}"
|
||||
local old_size
|
||||
old_size=$(du -sh "$logs_dir/$old" 2>/dev/null | cut -f1 | xargs)
|
||||
echo " - $old ($old_size)"
|
||||
to_delete+=("$logs_dir/$old")
|
||||
done
|
||||
fi
|
||||
group=()
|
||||
fi
|
||||
group+=("$dirname")
|
||||
prev_ide="$ide_name"
|
||||
done <<< "$sorted"
|
||||
|
||||
# Process the last group
|
||||
if [ ${#group[@]} -gt 0 ]; then
|
||||
local last_index=$(( ${#group[@]} - 1 ))
|
||||
local keep="${group[$last_index]}"
|
||||
local keep_size
|
||||
keep_size=$(du -sh "$logs_dir/$keep" 2>/dev/null | cut -f1 | xargs)
|
||||
echo " [$prev_ide]"
|
||||
echo " + $keep ($keep_size) [KEEP]"
|
||||
local i
|
||||
for ((i = 0; i < last_index; i++)); do
|
||||
local old="${group[$i]}"
|
||||
local old_size
|
||||
old_size=$(du -sh "$logs_dir/$old" 2>/dev/null | cut -f1 | xargs)
|
||||
echo " - $old ($old_size)"
|
||||
to_delete+=("$logs_dir/$old")
|
||||
done
|
||||
fi
|
||||
|
||||
if [ ${#to_delete[@]} -eq 0 ]; then
|
||||
echo " ✓ Không có log cũ để xóa."
|
||||
return
|
||||
fi
|
||||
|
||||
local confirm
|
||||
read -r -p " Xác nhận xóa ${#to_delete[@]} thư mục cũ? (Y/n): " confirm
|
||||
if [[ -n "$confirm" && ! "$confirm" =~ ^([yY]|[yY][eE][sS])$ ]]; then
|
||||
echo " Đã hủy."
|
||||
return
|
||||
fi
|
||||
|
||||
for d in "${to_delete[@]}"; do
|
||||
echo " Đã xóa: $(basename "$d")"
|
||||
rm -rf -- "$d"
|
||||
done
|
||||
}
|
||||
|
||||
# -----------------------------
|
||||
# Function: Cleanup pip cache
|
||||
# -----------------------------
|
||||
cleanup_pip() {
|
||||
echo "--- [Pip Cache] ---"
|
||||
if ! command -v pip3 &> /dev/null; then
|
||||
echo " ⚠ pip3 command not found."
|
||||
return
|
||||
fi
|
||||
|
||||
local cache_dir
|
||||
cache_dir=$(pip3 cache dir 2>/dev/null)
|
||||
if [ -d "$cache_dir" ]; then
|
||||
local size
|
||||
size=$(du -sh "$cache_dir" 2>/dev/null | cut -f1 | xargs)
|
||||
echo " $cache_dir"
|
||||
echo " ✗ Cache: $size"
|
||||
local confirm
|
||||
read -r -p " Xác nhận xóa? (Y/n): " confirm
|
||||
if [[ -n "$confirm" && ! "$confirm" =~ ^([yY]|[yY][eE][sS])$ ]]; then
|
||||
echo " Đã hủy."
|
||||
return
|
||||
fi
|
||||
pip3 cache purge 2>/dev/null
|
||||
echo " Đã xong."
|
||||
else
|
||||
echo " ✓ Cache rỗng."
|
||||
fi
|
||||
}
|
||||
|
||||
# -----------------------------
|
||||
# Function: Cleanup deno cache
|
||||
# -----------------------------
|
||||
cleanup_deno() {
|
||||
echo "--- [Deno Cache] ---"
|
||||
local deno_cache="$HOME/Library/Caches/deno"
|
||||
echo " $deno_cache"
|
||||
|
||||
if [ ! -d "$deno_cache" ]; then
|
||||
echo " ⚠ Thư mục không tồn tại."
|
||||
return
|
||||
fi
|
||||
|
||||
local size
|
||||
size=$(du -sh "$deno_cache" 2>/dev/null | cut -f1 | xargs)
|
||||
echo " ✗ Cache: $size"
|
||||
local confirm
|
||||
read -r -p " Xác nhận xóa? (Y/n): " confirm
|
||||
if [[ -n "$confirm" && ! "$confirm" =~ ^([yY]|[yY][eE][sS])$ ]]; then
|
||||
echo " Đã hủy."
|
||||
return
|
||||
fi
|
||||
rm -rf -- "$deno_cache"/*
|
||||
echo " Đã xong."
|
||||
}
|
||||
|
||||
# -----------------------------
|
||||
# Function: Cleanup go build cache
|
||||
# -----------------------------
|
||||
cleanup_go_build() {
|
||||
echo "--- [Go Build Cache] ---"
|
||||
if ! command -v go &> /dev/null; then
|
||||
echo " ⚠ go command not found."
|
||||
return
|
||||
fi
|
||||
|
||||
local cache_dir
|
||||
cache_dir=$(go env GOCACHE)
|
||||
if [ -d "$cache_dir" ]; then
|
||||
local size
|
||||
size=$(du -sh "$cache_dir" 2>/dev/null | cut -f1 | xargs)
|
||||
echo " $cache_dir"
|
||||
echo " ✗ Cache: $size"
|
||||
local confirm
|
||||
read -r -p " Xác nhận xóa? (Y/n): " confirm
|
||||
if [[ -n "$confirm" && ! "$confirm" =~ ^([yY]|[yY][eE][sS])$ ]]; then
|
||||
echo " Đã hủy."
|
||||
return
|
||||
fi
|
||||
go clean -cache
|
||||
echo " Đã xong."
|
||||
else
|
||||
echo " ✓ Cache rỗng."
|
||||
fi
|
||||
}
|
||||
|
||||
# -----------------------------
|
||||
# Function: Cleanup generic cache directory
|
||||
# $1 = label, $2 = đường dẫn thư mục
|
||||
# -----------------------------
|
||||
cleanup_cache_dir() {
|
||||
local label="$1"
|
||||
local cache_dir="$2"
|
||||
|
||||
echo "--- [$label Cache] ---"
|
||||
echo " $cache_dir"
|
||||
|
||||
if [ ! -d "$cache_dir" ]; then
|
||||
echo " ⚠ Thư mục không tồn tại."
|
||||
return
|
||||
fi
|
||||
|
||||
local size
|
||||
size=$(du -sh "$cache_dir" 2>/dev/null | cut -f1 | xargs)
|
||||
echo " ✗ Dung lượng: $size"
|
||||
local confirm
|
||||
read -r -p " Xác nhận xóa? (Y/n): " confirm
|
||||
if [[ -n "$confirm" && ! "$confirm" =~ ^([yY]|[yY][eE][sS])$ ]]; then
|
||||
echo " Đã hủy."
|
||||
return
|
||||
fi
|
||||
rm -rf -- "$cache_dir"/*
|
||||
echo " Đã xong."
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# Interactive Menu System
|
||||
# =============================================================================
|
||||
|
||||
# Tên các nhóm cleanup
|
||||
MENU_ITEMS=(
|
||||
"All"
|
||||
"Browsers (Edge, Mozilla, Playwright)"
|
||||
"IDE (VS Code, AntiGravity)"
|
||||
"Dev Caches (Go, NPM, Pip, Deno)"
|
||||
"IDE Logs (JetBrains, Google)"
|
||||
"Other Caches (Raspberry Pi)"
|
||||
"Homebrew"
|
||||
)
|
||||
|
||||
# Trạng thái chọn (0=off, 1=on), mặc định All=on
|
||||
MENU_SELECTED=(1 1 1 1 1 1 1)
|
||||
|
||||
MENU_CURSOR=0
|
||||
MENU_COUNT=${#MENU_ITEMS[@]}
|
||||
|
||||
# Vẽ menu lên terminal
|
||||
draw_menu() {
|
||||
# Di chuyển cursor lên đầu menu để vẽ lại
|
||||
if [ "$1" = "redraw" ]; then
|
||||
printf "\033[%dA" "$((MENU_COUNT + 2))"
|
||||
fi
|
||||
|
||||
echo " Chọn mục cần dọn dẹp (↑↓: di chuyển | Space: chọn/bỏ chọn | Enter: chạy các mục có [✓]):"
|
||||
echo ""
|
||||
|
||||
local i
|
||||
for ((i = 0; i < MENU_COUNT; i++)); do
|
||||
local prefix=" "
|
||||
[ $i -eq $MENU_CURSOR ] && prefix="▸ "
|
||||
|
||||
local check="[ ]"
|
||||
[ "${MENU_SELECTED[$i]}" -eq 1 ] && check="[✓]"
|
||||
|
||||
local label="${MENU_ITEMS[$i]}"
|
||||
|
||||
# In dòng, xóa hết ký tự cũ trên dòng
|
||||
printf "\r\033[K%s%s %s\n" "$prefix" "$check" "$label"
|
||||
done
|
||||
}
|
||||
|
||||
# Toggle All: chọn hoặc bỏ tất cả
|
||||
toggle_all() {
|
||||
local new_val="${MENU_SELECTED[0]}"
|
||||
# Nếu All đang bật → tắt hết, ngược lại → bật hết
|
||||
if [ "$new_val" -eq 1 ]; then
|
||||
new_val=0
|
||||
else
|
||||
new_val=1
|
||||
fi
|
||||
local i
|
||||
for ((i = 0; i < MENU_COUNT; i++)); do
|
||||
MENU_SELECTED[$i]=$new_val
|
||||
done
|
||||
}
|
||||
|
||||
# Cập nhật lại trạng thái All dựa trên các item con
|
||||
sync_all() {
|
||||
local all_on=1
|
||||
local i
|
||||
for ((i = 1; i < MENU_COUNT; i++)); do
|
||||
if [ "${MENU_SELECTED[$i]}" -eq 0 ]; then
|
||||
all_on=0
|
||||
break
|
||||
fi
|
||||
done
|
||||
MENU_SELECTED[0]=$all_on
|
||||
}
|
||||
|
||||
# Chạy interactive menu
|
||||
run_menu() {
|
||||
echo ""
|
||||
echo "===== 🧹 Cleanup macOS ====="
|
||||
echo ""
|
||||
|
||||
draw_menu
|
||||
|
||||
while true; do
|
||||
# Đọc 1 ký tự (không echo, không buffer)
|
||||
IFS= read -rsn1 key
|
||||
|
||||
case "$key" in
|
||||
# ESC sequence (arrow keys)
|
||||
$'\x1b')
|
||||
read -rsn2 seq
|
||||
case "$seq" in
|
||||
'[A') # Up
|
||||
MENU_CURSOR=$(( (MENU_CURSOR - 1 + MENU_COUNT) % MENU_COUNT ))
|
||||
;;
|
||||
'[B') # Down
|
||||
MENU_CURSOR=$(( (MENU_CURSOR + 1) % MENU_COUNT ))
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
# Space = toggle
|
||||
' ')
|
||||
if [ $MENU_CURSOR -eq 0 ]; then
|
||||
toggle_all
|
||||
else
|
||||
if [ "${MENU_SELECTED[$MENU_CURSOR]}" -eq 1 ]; then
|
||||
MENU_SELECTED[$MENU_CURSOR]=0
|
||||
else
|
||||
MENU_SELECTED[$MENU_CURSOR]=1
|
||||
fi
|
||||
sync_all
|
||||
fi
|
||||
;;
|
||||
# Enter = confirm
|
||||
'')
|
||||
echo ""
|
||||
break
|
||||
;;
|
||||
esac
|
||||
|
||||
draw_menu "redraw"
|
||||
done
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# Hàm chạy từng nhóm
|
||||
# =============================================================================
|
||||
|
||||
run_browsers() {
|
||||
cleanup_versions "Edge" "$HOME/Library/Application Support/Microsoft/EdgeUpdater/apps/msedge-stable"
|
||||
echo ""
|
||||
cleanup_versions "Edge Updater" "$HOME/Library/Application Support/Microsoft/EdgeUpdater/apps/msedge-updater"
|
||||
echo ""
|
||||
cleanup_cache_dir "Mozilla" "$HOME/Library/Caches/Mozilla"
|
||||
echo ""
|
||||
cleanup_cache_dir "Playwright" "$HOME/Library/Caches/ms-playwright"
|
||||
echo ""
|
||||
}
|
||||
|
||||
run_ide() {
|
||||
cleanup_vscode_extensions
|
||||
echo ""
|
||||
cleanup_vscode_cpptools
|
||||
echo ""
|
||||
cleanup_cache_dir "VS Code ShipIt" "$HOME/Library/Caches/com.microsoft.VSCode.ShipIt"
|
||||
echo ""
|
||||
cleanup_agy_recordings
|
||||
echo ""
|
||||
}
|
||||
|
||||
run_dev_caches() {
|
||||
cleanup_go
|
||||
echo ""
|
||||
cleanup_go_build
|
||||
echo ""
|
||||
cleanup_npm
|
||||
echo ""
|
||||
cleanup_pip
|
||||
echo ""
|
||||
cleanup_deno
|
||||
echo ""
|
||||
}
|
||||
|
||||
run_ide_logs() {
|
||||
cleanup_ide_logs "JetBrains" "$HOME/Library/Logs/JetBrains"
|
||||
echo ""
|
||||
cleanup_ide_logs "Google" "$HOME/Library/Logs/Google"
|
||||
echo ""
|
||||
}
|
||||
|
||||
run_other_caches() {
|
||||
cleanup_cache_dir "Raspberry Pi" "$HOME/Library/Caches/Raspberry Pi"
|
||||
echo ""
|
||||
}
|
||||
|
||||
run_homebrew() {
|
||||
cleanup_homebrew
|
||||
echo ""
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# Main
|
||||
# =============================================================================
|
||||
|
||||
# Map index → function
|
||||
GROUP_FUNCS=(
|
||||
"" # 0 = All (handled separately)
|
||||
"run_browsers" # 1
|
||||
"run_ide" # 2
|
||||
"run_dev_caches" # 3
|
||||
"run_ide_logs" # 4
|
||||
"run_other_caches" # 5
|
||||
"run_homebrew" # 6
|
||||
)
|
||||
|
||||
run_menu
|
||||
|
||||
# Kiểm tra có mục nào được chọn không
|
||||
has_selection=0
|
||||
for ((i = 1; i < MENU_COUNT; i++)); do
|
||||
if [ "${MENU_SELECTED[$i]}" -eq 1 ]; then
|
||||
has_selection=1
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$has_selection" -eq 0 ]; then
|
||||
echo "Không có mục nào được chọn. Thoát."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Chạy các nhóm đã chọn
|
||||
echo "===== Bắt đầu cleanup ====="
|
||||
echo ""
|
||||
|
||||
for ((i = 1; i < MENU_COUNT; i++)); do
|
||||
if [ "${MENU_SELECTED[$i]}" -eq 1 ]; then
|
||||
${GROUP_FUNCS[$i]}
|
||||
fi
|
||||
done
|
||||
|
||||
echo "===== ✅ Cleanup hoàn tất ====="
|
||||
@@ -0,0 +1,90 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# glm-quota — Check Zhipu AI (GLM) API quota
|
||||
#
|
||||
# Usage:
|
||||
# glm-quota # show quota
|
||||
# glm-quota -v # show raw JSON response
|
||||
#
|
||||
# Setup API key (Keychain):
|
||||
# security add-generic-password -a "$USER" -s GLM_API_KEY -w "YOUR_API_KEY"
|
||||
|
||||
KEY_NAME="GLM_API_KEY"
|
||||
URL="https://open.bigmodel.cn/api/monitor/usage/quota/limit"
|
||||
|
||||
# ===== COLORS =====
|
||||
GREEN="\033[1;32m"
|
||||
CYAN="\033[1;36m"
|
||||
YELLOW="\033[1;33m"
|
||||
RED="\033[1;31m"
|
||||
DIM="\033[2m"
|
||||
RESET="\033[0m"
|
||||
|
||||
# ===== ARGS =====
|
||||
VERBOSE=0
|
||||
[[ "$1" == "-v" ]] && VERBOSE=1
|
||||
|
||||
# ===== LOAD TOKEN =====
|
||||
API_TOKEN=$(security find-generic-password -a "$USER" -s "$KEY_NAME" -w 2>/dev/null | tr -d '\n')
|
||||
if [ -z "$API_TOKEN" ]; then
|
||||
echo -e "${RED}❌ API token not found in Keychain ($KEY_NAME)${RESET}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ===== CALL API =====
|
||||
RESPONSE=$(curl -s -H "Authorization: $API_TOKEN" "$URL")
|
||||
|
||||
if [ "$VERBOSE" -eq 1 ]; then
|
||||
echo -e "${YELLOW}🔧 Raw response:${RESET}"
|
||||
echo "$RESPONSE" | jq .
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# ===== PARSE =====
|
||||
SUCCESS=$(echo "$RESPONSE" | jq -r '.success // false')
|
||||
if [ "$SUCCESS" != "true" ]; then
|
||||
echo -e "${RED}❌ API request failed${RESET}"
|
||||
echo "$RESPONSE" | jq .
|
||||
exit 1
|
||||
fi
|
||||
|
||||
LEVEL=$(echo "$RESPONSE" | jq -r '.data.level // "unknown"')
|
||||
|
||||
# Extract TOKENS_LIMIT using jq in one shot
|
||||
read -r T_PERCENT T_RESET T_NUM < <(echo "$RESPONSE" | jq -r '
|
||||
.data.limits[] | select(.type == "TOKENS_LIMIT") |
|
||||
"\(.percentage // 0) \(.nextResetTime // 0) \(.number // 5)"
|
||||
')
|
||||
|
||||
# Extract TIME_LIMIT (web search) in one shot
|
||||
read -r R_USAGE R_CURRENT R_REMAINING R_PERCENT R_RESET < <(echo "$RESPONSE" | jq -r '
|
||||
.data.limits[] | select(.type == "TIME_LIMIT") |
|
||||
"\(.usage // 0) \(.currentValue // 0) \(.remaining // 0) \(.percentage // 0) \(.nextResetTime // 0)"
|
||||
')
|
||||
|
||||
# Convert millisecond timestamps to human readable
|
||||
format_ms() {
|
||||
local ms="$1"
|
||||
if [ -n "$ms" ] && [ "$ms" -gt 0 ] 2>/dev/null; then
|
||||
date -r $((ms / 1000)) "+%Y-%m-%d %H:%M:%S" 2>/dev/null || echo "$ms"
|
||||
else
|
||||
echo "N/A"
|
||||
fi
|
||||
}
|
||||
|
||||
T_RESET_HUMAN=$(format_ms "$T_RESET")
|
||||
R_RESET_HUMAN=$(format_ms "$R_RESET")
|
||||
|
||||
# ===== DISPLAY =====
|
||||
echo -e "${GREEN}✅ GLM Quota ${DIM}(account: ${LEVEL})${RESET}"
|
||||
|
||||
# -- Token Limit (main) --
|
||||
echo -e "\n${CYAN}[Token Limit — ${T_NUM}h rolling]${RESET}"
|
||||
echo -e " Usage: ${YELLOW}${T_PERCENT}%${RESET}"
|
||||
echo " Next Reset: $T_RESET_HUMAN"
|
||||
|
||||
# -- Web Search Limit (secondary) --
|
||||
if [ -n "$R_USAGE" ] && [ "$R_USAGE" != "0" ]; then
|
||||
echo -e "\n${DIM}[Web Search Limit — monthly]${RESET}"
|
||||
echo -e " ${DIM}Used: ${R_CURRENT}/${R_USAGE} (${R_PERCENT}%) | Reset: ${R_RESET_HUMAN}${RESET}"
|
||||
fi
|
||||
@@ -0,0 +1,33 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Function to run SSH command and handle errors
|
||||
run_ssh() {
|
||||
server=$1
|
||||
command=$2
|
||||
echo "===== $server ====="
|
||||
ssh -T $server "$command" &
|
||||
|
||||
# Capture the PID of the last background process
|
||||
pid=$!
|
||||
|
||||
# Wait for the background process to finish
|
||||
wait $pid
|
||||
|
||||
# Check the exit status of the background process
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "Successfully upgraded $server."
|
||||
else
|
||||
echo "Failed to upgrade $server. Check the connection and try again."
|
||||
fi
|
||||
}
|
||||
|
||||
# Run SSH commands for each server
|
||||
run_ssh "oc" 'sudo apt-get upgrade -y'
|
||||
run_ssh "tk" 'sudo apt-get upgrade -y'
|
||||
run_ssh "cc" 'sudo apt-get upgrade -y'
|
||||
run_ssh "rpi3" 'sudo apt-get upgrade -y'
|
||||
run_ssh "cse-z" 'sudo apt-get upgrade -y'
|
||||
run_ssh "hp" 'sudo apt-get upgrade -y'
|
||||
run_ssh "od-xu4" 'yay'
|
||||
|
||||
echo "Upgrade process completed for all servers."
|
||||
@@ -0,0 +1,27 @@
|
||||
#!/bin/bash
|
||||
# up-s.sh - Upload file lên server oc
|
||||
|
||||
if [ $# -ne 1 ]; then
|
||||
echo "Usage: $0 <local-file>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
LOCAL_FILE=$1
|
||||
REMOTE_HOST="oc"
|
||||
REMOTE_PATH="/app/thuanle.me/s.thuanle.me/data/"
|
||||
|
||||
if [ ! -f "$LOCAL_FILE" ]; then
|
||||
echo "Error: File '$LOCAL_FILE' không tồn tại."
|
||||
exit 2
|
||||
fi
|
||||
|
||||
echo "Đang upload $LOCAL_FILE lên $REMOTE_HOST:$REMOTE_PATH ..."
|
||||
scp "$LOCAL_FILE" "${REMOTE_HOST}:${REMOTE_PATH}"
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "Upload thành công."
|
||||
else
|
||||
echo "Upload thất bại."
|
||||
exit 3
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user