shell-bash
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseShell & Bash Scripting
Shell & Bash Scripting
Overview
概述
Shell scripting patterns for automation, system administration, and CLI tools.
适用于自动化、系统管理和CLI工具的Shell脚本模式。
Script Fundamentals
脚本基础
Script Structure
脚本结构
bash
#!/usr/bin/env bash
#bash
#!/usr/bin/env bash
#Script: backup.sh
Script: backup.sh
Description: Backup files to remote server
描述:将文件备份到远程服务器
Usage: ./backup.sh [options] <source> <destination>
使用方法:./backup.sh [选项] <源路径> <目标路径>
set -euo pipefail # Exit on error, undefined vars, pipe failures
IFS=$'\n\t' # Safer word splitting
set -euo pipefail # 遇到错误、未定义变量或管道失败时退出
IFS=$'\n\t' # 更安全的单词分割
Constants
常量
readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
readonly SCRIPT_NAME="$(basename "${BASH_SOURCE[0]}")"
readonly LOG_FILE="/var/log/${SCRIPT_NAME%.sh}.log"
readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
readonly SCRIPT_NAME="$(basename "${BASH_SOURCE[0]}")"
readonly LOG_FILE="/var/log/${SCRIPT_NAME%.sh}.log"
Default values
默认值
VERBOSE=false
DRY_RUN=false
COMPRESS=true
VERBOSE=false
DRY_RUN=false
COMPRESS=true
Cleanup on exit
退出时清理
cleanup() {
local exit_code=$?
# Cleanup temporary files
rm -f "${TEMP_FILE:-}"
exit "$exit_code"
}
trap cleanup EXIT
cleanup() {
local exit_code=$?
# 清理临时文件
rm -f "${TEMP_FILE:-}"
exit "$exit_code"
}
trap cleanup EXIT
Logging functions
日志函数
log() {
local level="$1"
shift
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [$level] $*" | tee -a "$LOG_FILE"
}
info() { log "INFO" "$@"; }
warn() { log "WARN" "$@" >&2; }
error() { log "ERROR" "$@" >&2; }
debug() { [[ "$VERBOSE" == true ]] && log "DEBUG" "$@" || true; }
die() {
error "$@"
exit 1
}
log() {
local level="$1"
shift
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [$level] $*" | tee -a "$LOG_FILE"
}
info() { log "INFO" "$@"; }
warn() { log "WARN" "$@" >&2; }
error() { log "ERROR" "$@" >&2; }
debug() { [[ "$VERBOSE" == true ]] && log "DEBUG" "$@" || true; }
die() {
error "$@"
exit 1
}
Usage
使用说明
usage() {
cat <<EOF
Usage: $SCRIPT_NAME [options] <source> <destination>
Options:
-v, --verbose Enable verbose output
-n, --dry-run Show what would be done
-h, --help Show this help message
Examples:
$SCRIPT_NAME /data /backup
$SCRIPT_NAME -v --dry-run /home/user /mnt/backup
EOF
}
usage() {
cat <<EOF
Usage: $SCRIPT_NAME [options] <source> <destination>
Options:
-v, --verbose 启用详细输出
-n, --dry-run 显示将要执行的操作
-h, --help 显示此帮助信息
Examples:
$SCRIPT_NAME /data /backup
$SCRIPT_NAME -v --dry-run /home/user /mnt/backup
EOF
}
Main function
主函数
main() {
parse_args "$@"
validate_inputs
perform_backup
}
main() {
parse_args "$@"
validate_inputs
perform_backup
}
Run main if script is executed directly
如果脚本直接执行则运行主函数
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
main "$@"
fi
undefinedif [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
main "$@"
fi
undefinedArgument Parsing
参数解析
bash
undefinedbash
undefinedUsing getopts (POSIX)
使用getopts(POSIX标准)
parse_args_getopts() {
while getopts ":vnh" opt; do
case $opt in
v) VERBOSE=true ;;
n) DRY_RUN=true ;;
h) usage; exit 0 ;;
?) die "Invalid option: -$OPTARG" ;;
:) die "Option -$OPTARG requires an argument" ;;
esac
done
shift $((OPTIND - 1))
SOURCE="${1:-}"
DESTINATION="${2:-}"}
parse_args_getopts() {
while getopts ":vnh" opt; do
case $opt in
v) VERBOSE=true ;;
n) DRY_RUN=true ;;
h) usage; exit 0 ;;
?) die "Invalid option: -$OPTARG" ;;
:) die "Option -$OPTARG requires an argument" ;;
esac
done
shift $((OPTIND - 1))
SOURCE="${1:-}"
DESTINATION="${2:-}"}
Using manual parsing (supports long options)
使用手动解析(支持长选项)
parse_args() {
while [[ $# -gt 0 ]]; do
case "$1" in
-v|--verbose)
VERBOSE=true
shift
;;
-n|--dry-run)
DRY_RUN=true
shift
;;
-c|--compress)
COMPRESS=true
shift
;;
--no-compress)
COMPRESS=false
shift
;;
-h|--help)
usage
exit 0
;;
--)
shift
break
;;
-*)
die "Unknown option: $1"
;;
*)
break
;;
esac
done
# Positional arguments
SOURCE="${1:-}"
DESTINATION="${2:-}"}
parse_args() {
while [[ $# -gt 0 ]]; do
case "$1" in
-v|--verbose)
VERBOSE=true
shift
;;
-n|--dry-run)
DRY_RUN=true
shift
;;
-c|--compress)
COMPRESS=true
shift
;;
--no-compress)
COMPRESS=false
shift
;;
-h|--help)
usage
exit 0
;;
--)
shift
break
;;
-*)
die "Unknown option: $1"
;;
*)
break
;;
esac
done
# 位置参数
SOURCE="${1:-}"
DESTINATION="${2:-}"}
Validation
验证
validate_inputs() {
[[ -z "$SOURCE" ]] && die "Source path is required"
[[ -z "$DESTINATION" ]] && die "Destination path is required"
[[ -e "$SOURCE" ]] || die "Source does not exist: $SOURCE"
}
---validate_inputs() {
[[ -z "$SOURCE" ]] && die "源路径是必填项"
[[ -z "$DESTINATION" ]] && die "目标路径是必填项"
[[ -e "$SOURCE" ]] || die "源路径不存在:$SOURCE"
}
---Variables and Data
变量与数据
Variable Operations
变量操作
bash
undefinedbash
undefinedVariable assignment
变量赋值
name="John"
readonly CONSTANT="immutable"
name="John"
readonly CONSTANT="immutable"
Default values
默认值
name="${name:-default}" # Use default if unset or empty
name="${name:=default}" # Assign default if unset or empty
name="${name:+alternative}" # Use alternative if set and non-empty
name="${name:?error message}" # Error if unset or empty
name="${name:-default}" # 如果未设置或为空则使用默认值
name="${name:=default}" # 如果未设置或为空则赋值默认值
name="${name:+alternative}" # 如果已设置且非空则使用替代值
name="${name:?error message}" # 如果未设置或为空则抛出错误
String manipulation
字符串操作
str="Hello, World!"
echo "${str:0:5}" # "Hello" (substring)
echo "${str: -6}" # "World!" (last 6 chars)
echo "${#str}" # 13 (length)
echo "${str/World/Bash}" # "Hello, Bash!" (replace first)
echo "${str//o/0}" # "Hell0, W0rld!" (replace all)
echo "${str#Hello, }" # "World!" (remove prefix)
echo "${str%!}" # "Hello, World" (remove suffix)
echo "${str^^}" # "HELLO, WORLD!" (uppercase)
echo "${str,,}" # "hello, world!" (lowercase)
str="Hello, World!"
echo "${str:0:5}" # "Hello"(子字符串)
echo "${str: -6}" # "World!"(最后6个字符)
echo "${#str}" # 13(长度)
echo "${str/World/Bash}" # "Hello, Bash!"(替换第一个匹配项)
echo "${str//o/0}" # "Hell0, W0rld!"(替换所有匹配项)
echo "${str#Hello, }" # "World!"(移除前缀)
echo "${str%!}" # "Hello, World"(移除后缀)
echo "${str^^}" # "HELLO, WORLD!"(转为大写)
echo "${str,,}" # "hello, world!"(转为小写)
Parameter expansion
参数展开
filename="/path/to/file.tar.gz"
echo "${filename##/}" # "file.tar.gz" (basename)
echo "${filename%/}" # "/path/to" (dirname)
echo "${filename%%.*}" # "/path/to/file" (remove all extensions)
echo "${filename%.gz}" # "/path/to/file.tar" (remove last extension)
undefinedfilename="/path/to/file.tar.gz"
echo "${filename##/}" # "file.tar.gz"(文件名)
echo "${filename%/}" # "/path/to"(目录名)
echo "${filename%%.*}" # "/path/to/file"(移除所有扩展名)
echo "${filename%.gz}" # "/path/to/file.tar"(移除最后一个扩展名)
undefinedArrays
数组
bash
undefinedbash
undefinedIndexed arrays
索引数组
declare -a fruits=("apple" "banana" "cherry")
fruits+=("date") # Append
echo "${fruits[0]}" # "apple" (first element)
echo "${fruits[-1]}" # "date" (last element)
echo "${fruits[@]}" # All elements
echo "${#fruits[@]}" # 4 (length)
echo "${!fruits[@]}" # 0 1 2 3 (indices)
declare -a fruits=("apple" "banana" "cherry")
fruits+=("date") # 追加元素
echo "${fruits[0]}" # "apple"(第一个元素)
echo "${fruits[-1]}" # "date"(最后一个元素)
echo "${fruits[@]}" # 所有元素
echo "${#fruits[@]}" # 4(数组长度)
echo "${!fruits[@]}" # 0 1 2 3(索引)
Iterate
遍历数组
for fruit in "${fruits[@]}"; do
echo "$fruit"
done
for fruit in "${fruits[@]}"; do
echo "$fruit"
done
With indices
使用索引遍历
for i in "${!fruits[@]}"; do
echo "$i: ${fruits[i]}"
done
for i in "${!fruits[@]}"; do
echo "$i: ${fruits[i]}"
done
Associative arrays (bash 4+)
关联数组(Bash 4+)
declare -A user=(
[name]="John"
[email]="john@example.com"
[age]=30
)
echo "${user[name]}" # "John"
echo "${!user[@]}" # Keys: name email age
echo "${user[@]}" # Values
declare -A user=(
[name]="John"
[email]="john@example.com"
[age]=30
)
echo "${user[name]}" # "John"
echo "${!user[@]}" # 键:name email age
echo "${user[@]}" # 值
Iterate key-value
遍历键值对
for key in "${!user[@]}"; do
echo "$key: ${user[$key]}"
done
for key in "${!user[@]}"; do
echo "$key: ${user[$key]}"
done
Array slicing
数组切片
echo "${fruits[@]:1:2}" # "banana" "cherry" (from index 1, 2 elements)
echo "${fruits[@]:1:2}" # "banana" "cherry"(从索引1开始,取2个元素)
Array filtering (bash 4+)
数组过滤(Bash 4+)
evens=()
for n in "${numbers[@]}"; do
(( n % 2 == 0 )) && evens+=("$n")
done
---evens=()
for n in "${numbers[@]}"; do
(( n % 2 == 0 )) && evens+=("$n")
done
---Control Flow
控制流
Conditionals
条件判断
bash
undefinedbash
undefinedTest operators
测试运算符
Strings
字符串
[[ -z "$str" ]] # Empty
[[ -n "$str" ]] # Not empty
[[ "$a" == "$b" ]] # Equal
[[ "$a" != "$b" ]] # Not equal
[[ "$a" < "$b" ]] # Less than (lexicographic)
[[ "$a" =~ ^[0-9]+$ ]] # Regex match
[[ -z "$str" ]] # 为空
[[ -n "$str" ]] # 不为空
[[ "$a" == "$b" ]] # 相等
[[ "$a" != "$b" ]] # 不相等
[[ "$a" < "$b" ]] # 小于(字典序)
[[ "$a" =~ ^[0-9]+$ ]] # 正则匹配
Numbers
数字
[[ "$a" -eq "$b" ]] # Equal
[[ "$a" -ne "$b" ]] # Not equal
[[ "$a" -lt "$b" ]] # Less than
[[ "$a" -le "$b" ]] # Less than or equal
[[ "$a" -gt "$b" ]] # Greater than
[[ "$a" -ge "$b" ]] # Greater than or equal
[[ "$a" -eq "$b" ]] # 相等
[[ "$a" -ne "$b" ]] # 不相等
[[ "$a" -lt "$b" ]] # 小于
[[ "$a" -le "$b" ]] # 小于等于
[[ "$a" -gt "$b" ]] # 大于
[[ "$a" -ge "$b" ]] # 大于等于
Files
文件
[[ -e "$file" ]] # Exists
[[ -f "$file" ]] # Regular file
[[ -d "$dir" ]] # Directory
[[ -r "$file" ]] # Readable
[[ -w "$file" ]] # Writable
[[ -x "$file" ]] # Executable
[[ -s "$file" ]] # Size > 0
[[ "$a" -nt "$b" ]] # Newer than
[[ "$a" -ot "$b" ]] # Older than
[[ -e "$file" ]] # 存在
[[ -f "$file" ]] # 普通文件
[[ -d "$dir" ]] # 目录
[[ -r "$file" ]] # 可读
[[ -w "$file" ]] # 可写
[[ -x "$file" ]] # 可执行
[[ -s "$file" ]] # 大小大于0
[[ "$a" -nt "$b" ]] # 比...新
[[ "$a" -ot "$b" ]] # 比...旧
If-elif-else
If-elif-else结构
if [[ "$status" == "success" ]]; then
echo "Success!"
elif [[ "$status" == "pending" ]]; then
echo "Still pending..."
else
echo "Failed"
fi
if [[ "$status" == "success" ]]; then
echo "成功!"
elif [[ "$status" == "pending" ]]; then
echo "仍在处理中..."
else
echo "失败"
fi
Case statement
Case语句
case "$command" in
start|begin)
start_service
;;
stop|end)
stop_service
;;
restart)
stop_service
start_service
;;
*)
echo "Unknown command: $command"
exit 1
;;
esac
case "$command" in
start|begin)
start_service
;;
stop|end)
stop_service
;;
restart)
stop_service
start_service
;;
*)
echo "未知命令:$command"
exit 1
;;
esac
Short-circuit
短路求值
[[ -f "$file" ]] && process_file "$file"
[[ -d "$dir" ]] || mkdir -p "$dir"
undefined[[ -f "$file" ]] && process_file "$file"
[[ -d "$dir" ]] || mkdir -p "$dir"
undefinedLoops
循环
bash
undefinedbash
undefinedFor loop
For循环
for item in item1 item2 item3; do
echo "$item"
done
for item in item1 item2 item3; do
echo "$item"
done
C-style for
C风格For循环
for ((i = 0; i < 10; i++)); do
echo "$i"
done
for ((i = 0; i < 10; i++)); do
echo "$i"
done
While loop
While循环
counter=0
while [[ $counter -lt 5 ]]; do
echo "$counter"
((counter++))
done
counter=0
while [[ $counter -lt 5 ]]; do
echo "$counter"
((counter++))
done
Read file line by line
逐行读取文件
while IFS= read -r line; do
echo "$line"
done < "$file"
while IFS= read -r line; do
echo "$line"
done < "$file"
Process command output
处理命令输出
while IFS= read -r file; do
echo "Processing: $file"
done < <(find . -name "*.txt")
while IFS= read -r file; do
echo "正在处理:$file"
done < <(find . -name "*.txt")
Until loop
Until循环
until [[ -f "$lockfile" ]]; do
sleep 1
done
until [[ -f "$lockfile" ]]; do
sleep 1
done
Break and continue
Break和Continue
for i in {1..10}; do
[[ $i -eq 5 ]] && continue
[[ $i -eq 8 ]] && break
echo "$i"
done
---for i in {1..10}; do
[[ $i -eq 5 ]] && continue
[[ $i -eq 8 ]] && break
echo "$i"
done
---Functions
函数
bash
undefinedbash
undefinedBasic function
基础函数
greet() {
local name="$1"
echo "Hello, $name!"
}
greet() {
local name="$1"
echo "你好,$name!"
}
Function with return value
带返回值的函数
is_valid_email() {
local email="$1"
[[ "$email" =~ ^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+.[A-Za-z]{2,}$ ]]
}
is_valid_email() {
local email="$1"
[[ "$email" =~ ^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+.[A-Za-z]{2,}$ ]]
}
Check return value
检查返回值
if is_valid_email "test@example.com"; then
echo "Valid email"
fi
if is_valid_email "test@example.com"; then
echo "有效的邮箱"
fi
Function with output capture
捕获输出的函数
get_user_count() {
wc -l < /etc/passwd
}
count=$(get_user_count)
get_user_count() {
wc -l < /etc/passwd
}
count=$(get_user_count)
Function with array parameter
带数组参数的函数
process_files() {
local -a files=("$@")
for file in "${files[@]}"; do
echo "Processing: $file"
done
}
process_files file1.txt file2.txt file3.txt
process_files() {
local -a files=("$@")
for file in "${files[@]}"; do
echo "正在处理:$file"
done
}
process_files file1.txt file2.txt file3.txt
Function with named reference (bash 4.3+)
带命名引用的函数(Bash 4.3+)
modify_array() {
local -n arr=$1
arr+=("new_element")
}
my_array=("a" "b" "c")
modify_array my_array
echo "${my_array[@]}" # "a b c new_element"
modify_array() {
local -n arr=$1
arr+=("new_element")
}
my_array=("a" "b" "c")
modify_array my_array
echo "${my_array[@]}" # "a b c new_element"
Error handling in functions
函数中的错误处理
safe_divide() {
local dividend="$1"
local divisor="$2"
if [[ "$divisor" -eq 0 ]]; then
echo "Error: Division by zero" >&2
return 1
fi
echo $((dividend / divisor))}
result=$(safe_divide 10 2) && echo "Result: $result"
---safe_divide() {
local dividend="$1"
local divisor="$2"
if [[ "$divisor" -eq 0 ]]; then
echo "错误:除以零" >&2
return 1
fi
echo $((dividend / divisor))}
result=$(safe_divide 10 2) && echo "结果:$result"
---Text Processing
文本处理
bash
undefinedbash
undefinedgrep - search patterns
grep - 搜索模式
grep "error" logfile.txt # Find lines with "error"
grep -i "error" logfile.txt # Case-insensitive
grep -E "error|warning" logfile.txt # Extended regex
grep -v "debug" logfile.txt # Invert match
grep -c "error" logfile.txt # Count matches
grep -l "error" *.log # List files with matches
grep -r "TODO" src/ # Recursive search
grep "error" logfile.txt # 查找包含"error"的行
grep -i "error" logfile.txt # 不区分大小写
grep -E "error|warning" logfile.txt # 使用扩展正则表达式
grep -v "debug" logfile.txt # 反向匹配
grep -c "error" logfile.txt # 统计匹配行数
grep -l "error" *.log # 列出包含匹配项的文件
grep -r "TODO" src/ # 递归搜索
sed - stream editor
sed - 流编辑器
sed 's/old/new/' file.txt # Replace first occurrence
sed 's/old/new/g' file.txt # Replace all
sed -i.bak 's/old/new/g' file.txt # In-place with backup
sed '/pattern/d' file.txt # Delete matching lines
sed -n '10,20p' file.txt # Print lines 10-20
sed 's/^/prefix: /' file.txt # Add prefix
sed 's/old/new/' file.txt # 替换第一个匹配项
sed 's/old/new/g' file.txt # 替换所有匹配项
sed -i.bak 's/old/new/g' file.txt # 原地替换并生成备份文件
sed '/pattern/d' file.txt # 删除匹配的行
sed -n '10,20p' file.txt # 打印第10到20行
sed 's/^/prefix: /' file.txt # 添加前缀
awk - field processing
awk - 字段处理
awk '{print $1}' file.txt # First field
awk -F: '{print $1}' /etc/passwd # Custom delimiter
awk '{sum += $1} END {print sum}' data.txt # Sum first column
awk 'NR > 1' file.txt # Skip header
awk '$3 > 100 {print $1, $3}' data.txt # Conditional print
awk '{print NR": "$0}' file.txt # Add line numbers
awk '{print $1}' file.txt # 第一个字段
awk -F: '{print $1}' /etc/passwd # 使用自定义分隔符
awk '{sum += $1} END {print sum}' data.txt # 求和第一列
awk 'NR > 1' file.txt # 跳过表头
awk '$3 > 100 {print $1, $3}' data.txt # 条件打印
awk '{print NR": "$0}' file.txt # 添加行号
cut - extract fields
cut - 提取字段
cut -d: -f1 /etc/passwd # First field
cut -c1-10 file.txt # Characters 1-10
cut -d, -f1,3 data.csv # Fields 1 and 3
cut -d: -f1 /etc/passwd # 第一个字段
cut -c1-10 file.txt # 第1到10个字符
cut -d, -f1,3 data.csv # 第1和第3个字段
sort and uniq
sort和uniq
sort file.txt # Sort lines
sort -n numbers.txt # Numeric sort
sort -r file.txt # Reverse sort
sort -t: -k3 -n /etc/passwd # Sort by field
uniq file.txt # Remove adjacent duplicates
sort file.txt | uniq -c # Count occurrences
sort file.txt | uniq -d # Show duplicates only
sort file.txt # 排序行
sort -n numbers.txt # 数值排序
sort -r file.txt # 反向排序
sort -t: -k3 -n /etc/passwd # 按字段排序
uniq file.txt # 移除相邻重复行
sort file.txt | uniq -c # 统计出现次数
sort file.txt | uniq -d # 仅显示重复行
tr - translate characters
tr - 字符转换
echo "hello" | tr 'a-z' 'A-Z' # Uppercase
tr -d '\r' < file.txt # Remove carriage returns
tr -s ' ' < file.txt # Squeeze spaces
echo "hello" | tr 'a-z' 'A-Z' # 转为大写
tr -d '\r' < file.txt # 移除回车符
tr -s ' ' < file.txt # 压缩连续空格
xargs - build commands
xargs - 构建命令
find . -name ".txt" | xargs wc -l
find . -name ".log" -print0 | xargs -0 rm
echo "a b c" | xargs -n1 echo
cat urls.txt | xargs -P4 -I{} curl {} # Parallel execution
---find . -name ".txt" | xargs wc -l
find . -name ".log" -print0 | xargs -0 rm
echo "a b c" | xargs -n1 echo
cat urls.txt | xargs -P4 -I{} curl {} # 并行执行
---Process Management
进程管理
bash
undefinedbash
undefinedBackground processes
后台进程
long_running_command &
pid=$! # Get PID of last background job
wait $pid # Wait for specific process
long_running_command &
pid=$! # 获取最后一个后台作业的PID
wait $pid # 等待指定进程完成
Run multiple in background and wait
运行多个后台进程并等待完成
for file in *.txt; do
process_file "$file" &
done
wait # Wait for all
for file in *.txt; do
process_file "$file" &
done
wait # 等待所有进程完成
Parallel processing with xargs
使用xargs进行并行处理
find . -name "*.jpg" -print0 | xargs -0 -P4 -I{} convert {} {}.png
find . -name "*.jpg" -print0 | xargs -0 -P4 -I{} convert {} {}.png
Job control
作业控制
jobs # List jobs
fg %1 # Bring job 1 to foreground
bg %1 # Resume job 1 in background
kill %1 # Kill job 1
jobs # 列出作业
fg %1 # 将作业1带到前台
bg %1 # 将作业1恢复到后台
kill %1 # 终止作业1
Process substitution
进程替换
diff <(sort file1.txt) <(sort file2.txt)
while read -r line; do
echo "$line"
done < <(command_that_outputs)
diff <(sort file1.txt) <(sort file2.txt)
while read -r line; do
echo "$line"
done < <(command_that_outputs)
Command groups
命令组
{ cmd1; cmd2; cmd3; } > output.txt # Group and redirect
( cd /tmp && cmd1; cmd2 ) # Subshell (doesn't affect current shell)
{ cmd1; cmd2; cmd3; } > output.txt # 分组并重定向输出
( cd /tmp && cmd1; cmd2 ) # 子shell(不影响当前shell)
Coprocesses
协进程
coproc my_coproc { while read -r line; do echo "Got: $line"; done; }
echo "Hello" >&"${my_coproc[1]}"
read -r response <&"${my_coproc[0]}"
---coproc my_coproc { while read -r line; do echo "Got: $line"; done; }
echo "Hello" >&"${my_coproc[1]}"
read -r response <&"${my_coproc[0]}"
---Related Skills
相关技能
- [[automation-scripts]] - Build automation
- [[devops-cicd]] - CI/CD pipelines
- [[development-environment]] - Environment setup
- [[automation-scripts]] - 构建自动化
- [[devops-cicd]] - CI/CD流水线
- [[development-environment]] - 环境搭建