shell 处理用户输入

本文围绕Bash脚本处理用户输入展开。介绍了传递参数,包括读取参数、脚本名及参数测试;特殊参数变量的统计与数据获取;移动参数的shift命令;处理选项的多种方法;获取用户输入的read命令及相关选项。还给出实战示例,总结了获取数据的多种途径。

处理用户输入


传递参数

#!/bin/bash
# Adding command-line parameters

if [ $# -ne 2 ] 
then
     echo Usage: $(basename $0) parameter1 parameter2
else
     total=$[ $1 + $2 ]
     echo $1 + $2 is $total
fi
exit

读取参数

$0 对应脚本名,$1 对应第一个命令行参数,$2 对应第二个命令行参数,以此类推,直到$9

#!/bin/bash
# Using one command-line parameter
factorial=1
for (( number = 1; number <= $1; number++ ))
do
     factorial=$[ $factorial * $number ]
done
echo The factorial of $1 is $factorial
exit

# Using two command-line parameters
product=$[ $1 * $2 ]
echo The first parameter is $1.
echo The second parameter is $2.
echo The product value is $product.
exit

参数之间是以空格分隔的,所以 shell 会将字符串包含的空格视为两个参数的分隔符。 要想在参数值中加入空格,必须使用引号(单引号或双引号均可)

#!/bin/bash
# Using one command-line string parameter

echo Hello $1, glad to meet you.
exit 

将文本字符串作为参数传递时,引号并不是数据的一部分,仅用于表明数据的起止位置

如果脚本需要的命令行参数不止 9 个,则仍可以继续加入更多的参数,但是需要稍微修改一 下位置变量名。在第 9 个位置变量之后,必须在变量名两侧加上花括号,比如${10}

#!/bin/bash
# Handling lots of command-line parameters

product=$[ ${10} * ${11} ]
echo The tenth parameter is ${10}.
echo The eleventh parameter is ${11}.
echo The product value is $product.
exit

读取脚本名

basename 命令可以返回不包含路径的脚本名

#!/bin/bash
# Using the $0 command-line parameter in messages

scriptname=$(basename $0)
echo The $scriptname run at $(date) >> $HOME/scripttrack.log
exit

参数测试

在使用位置变量之前一定要检查是否为空

#!/bin/bash
# Using one command-line parameter

if [ -n "$1" ]
then
     factorial=1
     for (( number = 1; number <= $1; number++ ))
     do
          factorial=$[ $factorial * $number ]
     done
     echo The factorial of $1 is $factorial
else
     echo "You did not provide a parameter."
fi
exit 

特殊参数变量

参数统计

特殊变量$#含有脚本运行时携带的命令行参数的个数

#!/bin/bash
# Counting command-line parameters

if [ $# -eq 1 ] 
then
     fragment="parameter was"
else
     fragment="parameters were"
fi
echo $# $fragment supplied.
exit

获取命令行中最后一个参数

#!/bin/bash
# Testing grabbing the last parameter

echo The number of parameters is $#
echo The last parameter is ${!#}
exit

当命令行中没有任何参数时,$#的值即为 0,但${!#}会返回命令行中的脚本名。

获取所有的数据

$*变量和$@变量可以轻松访问所有参数

∗ 变量会将所有的命令行参数视为一个单词。这个单词含有命令行中出现的每一个参数。基本上, *变量会将所有的命令行参数视为一个单词。这个单词含有命令行中出现的每一个参数。 基本上, 变量会将所有的命令行参数视为一个单词。这个单词含有命令行中出现的每一个参数。基本上,*变量会将这些参数视为一个整体,而不是一系列个体。

#!/bin/bash
# Testing different methods for grabbing all the parameters

echo
echo "Using the \$* method: $*"
echo 
echo "Using the \$@ method: $@"
echo 
exit

$@变量会将所有的命令行参数视为同一字符串中的多个独立的单词

#!/bin/bash
# Exploring different methods for grabbing all the parameters

echo
echo "Using the \$* method: $*"
count=1
for param in "$*"
do
     echo "\$* Parameter #$count = $param"
     count=$[ $count + 1 ]
done

echo 
echo "Using the \$@ method: $@"
count=1
for param in "$@"
do
     echo "\$@ Parameter #$count = $param"
     count=$[ $count + 1 ]
done
echo 
exit

$*变量会将所有参数视为单个参数,而$@变量会单独处理每个参数

这里再详细说明一下$*$@的区别。当$*出现在双引号内时,会被扩展成由多个命令行参数组成的单个单词,每 个参数之间以 IFS 变量值的第一个字符分隔,也就是说,$*会被扩展"$1c 2 c . . " ( 其中 c 是 I F S 变量值的第一个字符 ) 。当 ‘ 2c.."(其中 c 是 IFS 变量值 的第一个字符)。当` 2c.."(其中cIFS变量值的第一个字符)。当@出现在双引号内时,其所包含的各个命令行参数会被扩展成独立的单词,也就是说,$@`会被扩展为"$1"“$2”

移动参数

在使用 shift 命令时,默认情况下会将每个位置的变量值都向左移动一个位置。因此,变 量$3 的值会移入$2,变量$2 的值会移入$1,而变量$1 的值则会被删除(注意,变量$0 的值, 也就是脚本名,不会改变)。

#!/bin/bash
# Shifting through the parameters

echo 
echo "Using the shift method:"
count=1
while [ -n "$1" ]
do
     echo "Parameter #$count = $1"
     count=$[ $count + 1 ]
     shift
done
echo 
exit

使用 shift 命令时要小心。如果某个参数被移出,那么它的值就被丢弃了,无法再恢复。

也可以一次性移动多个位置。只需给 shift 命令提供一个参数,指明要移动的位置 数即可

#!/bin/bash
# Shifting mulitiple positions through the parameters

echo 
echo "The original parameters: $*"
echo "Now shifting 2..."
shift 2
echo "Here's the new first parameter: $1"
echo
exit

处理选项

查找选项

处理简单选项

#!/bin/bash
# Extract command-line options

echo 
while [ -n "$1" ]
do
     case "$1" in
          -a) echo "Found the -a option" ;;
          -b) echo "Found the -b option" ;;
          -c) echo "Found the -c option" ;;
          *) echo "$1 is not an option" ;;
     esac
     shift
done
echo 
exit

分离参数和选项

#!/bin/bash
# Extract command-line options and parameters

echo 
while [ -n "$1" ]
do
     case "$1" in
          -a) echo "Found the -a option" ;;
          -b) echo "Found the -b option" ;;
          -c) echo "Found the -c option" ;;
          --) shift
              break;;
          *) echo "$1 is not an option" ;;
     esac
     shift
done
#
echo
count=1
for param in $@
do
     echo "Parameter #$count: $param"
     count=$[ $count + 1 ]
done
echo 
exit

处理含值的选项

#!/bin/bash
# Extract command-line options and values

echo 
while [ -n "$1" ]
do
     case "$1" in
          -a) echo "Found the -a option" ;;
          -b) param=$2 
              echo "Found the -b option with parameter value $param" 
              shift;;
          -c) echo "Found the -c option" ;;
          --) shift
              break;;
          *) echo "$1 is not an option" ;;
     esac
     shift
done
#
echo
count=1
for param in $@
do
     echo "Parameter #$count: $param"
     count=$[ $count + 1 ]
done
exit

使用getopt命令

getopt optstring parameters

#!/bin/bash
# Extract command-line options and values with getopt

set -- $(getopt -q ab:cd "$@")

echo 
while [ -n "$1" ]
do
     case "$1" in
          -a) echo "Found the -a option" ;;
          -b) param=$2 
              echo "Found the -b option with parameter value $param" 
              shift;;
          -c) echo "Found the -c option" ;;
          --) shift
              break;;
          *) echo "$1 is not an option" ;;
     esac
     shift
done

echo
count=1
for param in $@
do
     echo "Parameter #$count: $param"
     count=$[ $count + 1 ]
done
exit

使用getopts命令

getopts optstring variable

#!/bin/bash
# Extract command-line options and values with getopts

echo 
while getopts :ab:c opt
do
     case "$opt" in
          a) echo "Found the -a option" ;;
          b) echo "Found the -b option with parameter value $OPTARG";;
          c) echo "Found the -c option" ;;
          *) echo "Unknown option: $opt" ;;
     esac
done
exit

获取用户输入

基本的读取

read 命令从标准输入(键盘)或另一个文件描述符中接受输入。获取输入后,read 命令会 将数据存入变量。

#!/bin/bash
# Using the read command with REPLY variable

read -p "Enter your name: "
echo
echo "Hello $REPLY, welcome to my script."
exit

超时

使用 read 命令时要当心。脚本可能会一直苦等着用户输入。如果不管是否有数据输入,脚 本都必须继续执行,你可以用-t 选项来指定一个计时器。-t 选项会指定 read 命令等待输入的 秒数。如果计时器超时,则 read 命令会返回非 0 退出状态码

#!/bin/bash
# Using the read command with a timer

if read -t 5 -p "Enter your name: " name
then
     echo "Hello $name, welcome to my script."
else
     echo
     echo "Sorry, no longer waiting for name."
fi
exit

无显示读取

-s 选项可以避免在 read 命令中输入的数据出现在屏幕上(其实数据还是会被显示,只不 过 read 命令将文本颜色设成了跟背景色一样)。

#!/bin/bash
# Hiding input data

read -s -p "Enter your password: " pass
echo
echo "Your password is $pass"
exit

从文件中读取

#!/bin/bash
# Using the read command to read a file

count=1
cat $HOME/scripts/test.txt | while read line
do
     echo "Line $count: $line"
     count=$[ $count + 1 ]
done
echo "Finished processing the file."
exit

实战

该脚本在处理用户输入的同时,使用 ping 命令或 ping6 命令 来测试与其他网络主机的连通性

#!/bin/bash
# Check systems on local network
# allowing for a variety of input
# methods.


########### Determine Input Method ###################


# Check for command-line options here using getopts. 
# If none, then go on to File Input Method

while getopts t: opt 
do
     case "$opt" in
          t) # Found the -t option 
             if [ $OPTARG = "IPv4" ]
             then
                  pingcommand=$(which ping)
             
             elif [ $OPTARG = "IPv6" ]
             then
                  pingcommand=$(which ping6)
             
             else
                  echo "Usage: -t IPv4 or -t IPv6"
                  echo "Exiting script..."
                  exit
             fi
             ;;
          *) echo "Usage: -t IPv4 or -t IPv6"
             echo "Exiting script..."
             exit;;
     esac
     
     shift $[ $OPTIND - 1 ]
     
     if [ $# -eq 0 ]
     then
          echo
          echo "IP Address(es) parameters are missing."
          echo
          echo "Exiting script..."
          exit
     fi

     for ipaddress in "$@"
     do
          echo
          echo "Checking system at $ipaddress..."
          echo
          $pingcommand -q -c 3 $ipaddress
          echo
     done
     exit
done

########### File Input Method ###################

echo
echo "Please enter the file name with an absolute directory reference..."
echo
choice=0
while [ $choice -eq 0 ] 
do
     read -t 60 -p "Enter name of file: " filename
     if [ -z $filename ]
     then
          quitanswer=""
          read -t 10 -n 1 -p "Quit script [Y/n]? " quitanswer
          #
          case $quitanswer in 
          Y | y) echo
                 echo "Quitting script..."
                 exit;;
          N | n) echo
                 echo "Please answer question: "
                 choice=0;;
          *)     echo 
                 echo "No response. Quitting script..."
                 exit;;
          esac
     else
          choice=1
     fi
done

if [ -s $filename ] && [ -r $filename ]
     then
          echo "$filename is a file, is readable, and is not empty."
          echo
          cat $filename | while read line
          do
               ipaddress=$line
               read line
               iptype=$line
               if [ $iptype = "IPv4" ]
               then
                    pingcommand=$(which ping)
               else
                    pingcommand=$(which ping6)
               fi
               echo "Checking system at $ipaddress..."
               $pingcommand -q -c 3 $ipaddress
               echo
          done
          echo "Finished processing the file. All systems checked."
     else
          echo 
          echo "$filename is either not a file, is empty, or is"
          echo "not readable by you. Exiting script..."
fi 
#################### Exit Script #####################
exit

小结

本章展示了从脚本用户处获取数据的 3 种方法。命令行参数允许用户运行脚本时直接在命令 行中输入数据。脚本可通过位置变量获取命令行参数。

shift 命令通过对位置变量进行轮转(rotating)的方式来操作命令行参数。就算不知道参 数的数量,也可以轻松遍历所有参数。

有 3 个特殊变量可以用来处理命令行参数。shell 会将KaTeX parse error: Expected 'EOF', got '#' at position 1: #̲变量设为命令行参数的个数。*变 量会将所有命令行参数保存为一个字符串。$@变量会将所有命令行参数保存为独立的单词。这些 变量在处理参数列表时非常有用。

除了命令行参数,还可以通过命令行选项向脚本传递信息。命令行选项是以连字符起始的单 个字母。可以使用不同选项改变脚本的行为。

bash shell 提供了 3 种方法来处理命令行选项。第一种方法是将其像命令行参数一样处理。利 用位置变量遍历选项并进行相应的处理。第二种方法是使用 getopt 将命令行选项和参数转换成 可以在脚本中处理的标准格式。最后一种方法是使用拥有更多高级功能的 getopts 命令。

read 命令能够以交互式方法从脚本用户处获得数据。该命令允许脚本向用户询问并等待用 户回答。read 命令会将脚本用户输入的数据存入一个或多个变量,以方便在脚本中使用。

read 命令有一些选项支持自定义脚本的输入数据,比如不显示用户输入、超时选项以及限 制输入的字符数量。

<think>好的,我现在需要帮助用户解决在Shell程序中如何处理用户输入的特殊字符的问题。首先,我需要回顾用户之前的对话历史和已有的引用内容,确保回答准确并符合用户需求。 用户在上一次的问题中提到了错误信息,关于创建子进程时文本为空的问题,现在转向了如何处理Shell中的特殊字符。之前的回答中引用了三个文献,分别涉及转义符、read命令和管道符的使用。这些引用需要整合到当前的回答中。 首先,我应该明确Shell中特殊字符的类型,比如元字符、通配符、管道符等,这些字符在Shell中有特殊意义,直接输入可能导致意外行为。用户需要知道如何处理这些字符,避免它们被Shell解释,而是作为普通字符处理。 根据引用[1],Shell提供了三种转义符:单引号、双引号和反斜杠。需要详细说明每种方法的使用场景和区别。例如,单引号会关闭所有特殊字符,而双引号允许变量替换和命令替换。反斜杠则用于转义单个字符。 接下来,用户提到的read命令处理输入(引用[2]),需要说明如何在脚本中使用read命令安全地获取输入,特别是当输入包含特殊字符时。可能需要使用-r选项来防止反斜杠转义,以及使用双引号包裹变量避免分词。 另外,引用[3]提到了管道符的使用,但当前问题更关注输入处理,因此可能需要提到如何在管道中传递包含特殊字符的参数,但重点还是用户直接输入的情况。 用户的需求可能包括如何转义字符、如何安全读取输入、以及处理带特殊字符的参数。需要分步骤说明,结合代码示例,如使用单引号、双引号、反斜杠,以及read命令的最佳实践。 还要考虑不同场景下的处理方式,比如在命令行直接处理、在脚本中处理,或者通过函数传递参数。需要提醒用户注意事项,比如避免未引用的变量扩展,正确处理文件名中的空格等。 需要确保回答结构清晰,步骤明确,每个方法都有示例代码,并引用相关文献。同时,生成的相关问题要符合逻辑,可能涉及其他Shell编程中的常见问题,如参数扩展、命令替换的安全处理等。 最后,检查是否符合系统级指令:使用正确的中文,数学公式用$...$,独立公式用$$...$$,引用标记正确,没有使用Markdown格式,代码块正确,相关问题部分合理。</think>### Shell处理用户输入特殊字符的方法详解 在Shell编程中处理特殊字符的核心原则是:通过转义机制和引用规则,控制字符的解释方式。以下是具体实现方法及示例代码(整合引用[1][2][3]内容): #### 一、基础转义方法 1. **单引号硬转义** 关闭所有特殊字符解释,包括:$ ` \ 等 ```bash echo '特殊字符$`\' # 输出:特殊字符$`\ ``` 2. **双引号软转义** 允许以下字符保持特殊含义:$ ` \ ```bash name="World" echo "Hello $name" # 输出:Hello World echo "当前目录:`pwd`" # 执行命令替换 ``` 3. **反斜杠转义** 对单个字符进行转义,适用于混合内容: ```bash echo 单价:\$50\*10 # 输出:单价:$50*10 ``` #### 二、安全输入处理 1. **read命令最佳实践** 使用`-r`选项禁用反斜杠转义,配合IFS控制分隔符: ```bash IFS= read -r -p "输入路径:" path echo "处理后的路径:$path" # 保留所有特殊字符 ``` 2. **参数传递处理** 处理包含空格等特殊字符的参数时: ```bash # 正确方式 process_file "My Document.txt" # 保留文件名中的空格 # 错误方式 process_file My Document.txt # 被解析为两个参数 ``` #### 三、动态内容处理 1. **printf格式化输出** 安全生成含特殊字符的内容: ```bash printf "包含换行符的文本\n第二行内容\n" > output.txt ``` 2. **Here Document处理** 安全输入多行文本: ```bash cat << 'EOF' > config.cfg PATH="/usr/local/bin:$PATH" KEY='secret$value' EOF ``` #### 四、数学表达式验证 对于需要处理特殊字符的命令参数,应满足: $$ \forall c \in InputString,\ \exists esc \in \{ ', ", \\ \} \quad s.t. \quad esc(c) \rightarrow Literal $$ 其中: - $esc()$ 表示转义操作 - $Literal$ 表示字符的字面值 #### 五、注意事项 1. 避免未引用的变量扩展 ```bash # 危险操作 rm $filename # 如果filename包含空格或通配符会出错 # 安全操作 rm -- "$filename" ``` 2. 文件名处理规范 ```bash find . -name '*.log' -exec grep -F 'error' {} + # 正确处理含空格文件名 ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值