命令解析
如何用shell来做一个命令行工具。最简单的,可能是判断用户的输入 $?,另外还有 getopt函数。本文收集了多个shell的命令行解析方式。
脚本首行的,set -o errexit不确定是什么作用。
set
-e 脚本中的命令一旦运行失败就终止脚本的执行
-x 用于显示出命令与其执行结果(默认shell脚本中只显示执行结果)
#!/bin/bash
set -x
echo "Hello World !"
效果就是,执行一行,输出当前正在执行的命令。 其实效果和sh -x xx.sh一样会打印执行过程
执行效果为:
+ echo Hello World !
Hello World !
set -e 遇到错误就终止执行。
FROM nginx:1.19
RUN set -ex \
&& rm -rf /etc/nginx/conf.d/default.conf
case + shift
示例1
以下示例,演示如何在shell中解析命令,例子来源istio-1.9.3提供的示例代码。*)可以完善为提示工具用法。
#!/bin/bash
set -euo pipefail
INCLUDE_SERVICE=${INCLUDE_SERVICE:-"true"}
INCLUDE_DEPLOYMENT=${INCLUDE_DEPLOYMENT:-"true"}
SERVICE_VERSION=${SERVICE_VERSION:-"v1"}
while (( "$#" )); do
case "$1" in
--version)
SERVICE_VERSION=$2
shift 2
;;
--includeService)
INCLUDE_SERVICE=$2
shift 2
;;
--includeDeployment)
INCLUDE_DEPLOYMENT=$2
shift 2
;;
*)
echo "Error: Unsupported flag $1" >&2
exit 1
;;
esac
done
SERVICE_YAML=$(cat <<EOF
apiVersion: v1
kind: Service
metadata:
name: helloworld
labels:
app: helloworld
service: helloworld
spec:
ports:
- port: 5000
name: http
selector:
app: helloworld
EOF
)
DEPLOYMENT_YAML=$(cat <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: helloworld-${SERVICE_VERSION}
labels:
app: helloworld
version: ${SERVICE_VERSION}
spec:
replicas: 1
selector:
matchLabels:
app: helloworld
version: ${SERVICE_VERSION}
template:
metadata:
labels:
app: helloworld
version: ${SERVICE_VERSION}
spec:
containers:
- name: helloworld
env:
- name: SERVICE_VERSION
value: ${SERVICE_VERSION}
image: docker.io/istio/examples-helloworld-v1
resources:
requests:
cpu: "100m"
imagePullPolicy: IfNotPresent
ports:
- containerPort: 5000
EOF
)
OUT=""
# Add the service to the output.
if [[ "$INCLUDE_SERVICE" == "true" ]]; then
OUT="${SERVICE_YAML}"
fi
# Add the deployment to the output.
if [[ "$INCLUDE_DEPLOYMENT" == "true" ]]; then
# Add a separator
if [[ -n "$OUT" ]]; then
OUT+="
---
"
fi
OUT+="${DEPLOYMENT_YAML}"
fi
echo "$OUT"
示例2
下面这个例子,使用了$@,函数,等功能。
#!/usr/bin/env bash
# start containers
function up {
docker-compose up -d $@
}
# stop containers
function down {
docker-compose down
}
# initialize application
function init {
echo "Stating Initialization..."
echo "Copy .env file..."
cp .env.example .env
echo "Install PHP dependencies..."
docker-compose run roadrunner sh -c 'composer require spiral/roadrunner:${RR_VERSION}'
echo "Initialization completed!"
}
# login to container
function login {
container=${1:-roadrunner}
echo "Attempt to login ${container} container..."
docker-compose exec ${container} bash
}
# show container logs
function logs {
docker-compose logs $1
}
# execute RoadRunner command
function rr {
docker-compose exec roadrunner rr -c /etc/rr.yaml $1
}
subcommand=$1
shift
case $subcommand in
up)
up $@
;;
down)
down
;;
init)
init
;;
login)
login $1
;;
logs)
logs $1
;;
rr)
rr $1
;;
*)
echo "help"
;;
esac
为了演示上面的用到的一些功能,我写了如下一个例子。最终,使用bash cmd.sh zhang shuo ai wo 来调用一下。(所以,我们发现,脚本在函数功,还支持默认参数功能。)
#!/bin/bash
# 函数内的,只能显示,调用该函数的参数,而不是脚本传入的参数 。
function hello {
echo $#
echo $1
echo $2
echo $3
echo $@
}
function init {
#msg=${1:-defaultmsg} # 相当于指定了默认参数。
msg=${1:-defaultmsg some}
echo $msg
}
echo $@
shift # 该参数,会移除传入脚本的第1个参数,前后两个命令正好对比。
echo $@
hello liu xiao ming
# init 必须要先定义才能使用
init
init custom_msg
示例3
echo -e "a\nb\nc" 是可以支持使用转义符号的。
shell里面直接调用另外一个脚本,(把它想象成,在shell中执行命令,绝对路径访问即可)
set -o errexit
display_usage() {
echo
echo "USAGE: ./build_push_update_images.sh <version> [-h|--help] [--prefix=value] [--scan-images]"
echo " version : Version of the sample app images (Required)"
echo " -h|--help : Prints usage information"
echo " --prefix: Use the value as the prefix for image names. By default, 'istio' is used"
echo -e " --scan-images : Enable security vulnerability scans for docker images \n\t\t\trelated to bookinfo sample apps. By default, this feature \n\t\t\tis disabled."
exit 1
}
# Check if there is atleast one input argument
if [[ -z "$1" ]] ; then
echo "Missing version parameter"
display_usage
else
VERSION="$1"
shift
fi
# Process the input arguments. By default, image scanning is disabled.
PREFIX=istio
ENABLE_IMAGE_SCAN=false
echo "$@"
for i in "$@"
do
case "$i" in
--prefix=* )
PREFIX="${i#--prefix=}" ;;
--scan-images )
ENABLE_IMAGE_SCAN=true ;;
-h|--help )
echo
echo "Build the docker images for bookinfo sample apps, push them to docker hub and update the yaml files."
display_usage ;;
* )
echo "Unknown argument: $i"
display_usage ;;
esac
done
#Build docker images 直接调用,另外一个脚本
src/build-services.sh "${VERSION}" "${PREFIX}"
getopts
示例1
#!/bin/bash
usage () {
echo -e "\033[31mIMPORTANT: Run As Root\033[0m"
echo ""
echo "Usage: docker.sh [OPTIONS]"
echo ""
echo "A docker written by shell"
echo ""
echo "Options:"
echo " -c string docker command"
echo " (\"run\")"
echo " -m memory"
echo " (\"100M, 200M, 300M...\")"
echo " -C string container name"
echo " -I string image name"
echo " -V string volume"
echo " -P string program to run in container"
return 0
}
if test "$(whoami)" != root
then
usage
exit -1
fi
while getopts c:m:C:I:V:P: option
do
case "$option"
in
c) cmd=$OPTARG;;
m) memory=$OPTARG;;
C) container=$OPTARG;;
I) image=$OPTARG;;
V) volume=$OPTARG;;
P) program=$OPTARG;;
\?) usage
exit -2;;
esac
done
export cmd=$cmd
export memory=$memory
export container=$container
export image=$image
export volume=$volume
export program=$program
unshare --uts --mount --pid --fork ./container.sh