python中的fire和Linux shell中的参数传递

一、fire

安装

要使用 Python Fire 库,首先需要安装它。以下是安装步骤:

使用 pip 安装

可以通过 pip 直接安装 Python Fire:

python 复制代码
pip install fire

特性

  1. 自动生成命令行界面:将任何 Python 对象(函数、类、模块、字典等)自动转换为命令行界面。

  2. 简洁性:只需一行代码即可生成命令行界面,大大减少了开发时间和代码复杂度。

  3. 灵活性:支持多种数据类型和参数,能够处理复杂的命令行需求。

  4. 易用性:与 Python 标准库无缝集成,易于上手和使用。

基本功能

将函数转换为命令行工具

可以将一个简单的函数转换为命令行工具:

python 复制代码
import fire

def greet(name):
    return f'Hello, {name}!'

if __name__ == '__main__':
    fire.Fire(greet)

在命令行中运行:

python 复制代码
python greet.py John

输出:

python 复制代码
Hello, John!

将类转换为命令行工具

可以将一个类转换为命令行工具:

python 复制代码
import fire

class Calculator:
    def add(self, a, b):
        return a + b

    def multiply(self, a, b):
        return a * b

if __name__ == '__main__':
    fire.Fire(Calculator)

在命令行中运行:

python 复制代码
python calculator.py add 2 3
python calculator.py multiply 2 3

输出:

python 复制代码
5
6

将字典转换为命令行工具

可以将一个字典转换为命令行工具:

python 复制代码
import fire

operations = {
    'add': lambda a, b: a + b,
    'multiply': lambda a, b: a * b,
}

if __name__ == '__main__':
    fire.Fire(operations)

在命令行中运行:

python 复制代码
python operations.py add 2 3
python operations.py multiply 2 3

输出:

python 复制代码
5
6

高级功能

处理复杂的数据类型

Python Fire 支持处理复杂的数据类型,如列表、字典等:

python 复制代码
import fire

def process_list(items):
    return [item.upper() for item in items]

if __name__ == '__main__':
    fire.Fire(process_list)

在命令行中运行:

python 复制代码
python process_list.py --items a b c

输出:

python 复制代码
['A', 'B', 'C']

使用嵌套命令

可以使用嵌套命令来处理复杂的命令行操作:

python 复制代码
import fire

class FileManager:
    def read(self, filename):
        with open(filename, 'r') as file:
            return file.read()

    def write(self, filename, content):
        with open(filename, 'w') as file:
            file.write(content)
        return f'{filename} has been written.'

if __name__ == '__main__':
    fire.Fire(FileManager)

在命令行中运行:

python 复制代码
python filemanager.py read test.txt
python filemanager.py write test.txt "Hello, World!"

自定义命令行参数

可以自定义命令行参数,提供更多控制和灵活性:

python 复制代码
import fire

def greet(name, greeting='Hello'):
    return f'{greeting}, {name}!'

if __name__ == '__main__':
    fire.Fire(greet)

在命令行中运行:

python 复制代码
python greet.py John --greeting Hi

输出:

python 复制代码
Hi, John!

实际应用场景

数据处理脚本

在数据处理脚本中,通过 Python Fire 将函数或类转换为命令行工具,简化数据处理流程。

python 复制代码
import fire
import pandas as pd

def process_data(filename):
    df = pd.read_csv(filename)
    df['processed'] = df['data'] * 2
    df.to_csv('processed_' + filename, index=False)
    return 'Data processed.'

if __name__ == '__main__':
    fire.Fire(process_data)

在命令行中运行:

python 复制代码
python process_data.py data.csv

自动化运维脚本

在自动化运维脚本中,通过 Python Fire 将类转换为命令行工具,简化服务器管理和运维操作。

python 复制代码
import fire
import os

class ServerManager:
    def start(self, service):
        os.system(f'systemctl start {service}')
        return f'{service} started.'

    def stop(self, service):
        os.system(f'systemctl stop {service}')
        return f'{service} stopped.'

if __name__ == '__main__':
    fire.Fire(ServerManager)

在命令行中运行:

python 复制代码
python server_manager.py start nginx
python server_manager.py stop nginx

开发测试工具

在开发测试工具中,通过 Python Fire 将函数或类转换为命令行工具,简化测试流程。

python 复制代码
import fire
import requests

def test_api(endpoint):
    response = requests.get(endpoint)
    return response.json()

if __name__ == '__main__':
    fire.Fire(test_api)

在命令行中运行:

python 复制代码
python test_api.py https://api.example.com/data

二、Linux shell 中传递参数

来自命令行的参数传递

有时候 shell 脚本需要与用户进行交互,传递参数以供脚本读取,这时候就需要了解参数传递的过程。

传递参数的语法:./int.sh $HOME/LearningPerl/* 10

以上向脚本int.sh传递了两个参数,参数之间及参数和脚本之间用空格分开。参数之间的前后顺序也有规定的,这些称为位置参数,之所以说参数之间的顺序有规定,使因为其存入特殊变量不同,也就导致后续应用参数时的不同。

存入位置参数的特殊变量分别是:$1是第一个参数,$2是第二个参数,...,直到第九个参数$9,而$0是程序名,也就是脚本名。

因为参数之间是空格间隔的,所以当参数含有空格时 ,需要引号(单引号或双引号均可)将其圈起来。

bash 复制代码
#!/bin/bash
echo "I'm learning $1!"
bash 复制代码
./int.sh 'Linux shell'
# I'm learning Linux shell!

当传入的参数超过 ≥10 个时,这时就会有引用上的歧义,这个后面遇到再说何为歧义,这时候需要用花括号${}将 10 括起来,让 shell 知道你要引用第 10 个参数。

例如:

bash 复制代码
#!/bin/bash
echo "The tenth parameter is ${10}"
bash 复制代码
./int.sh 1 2 3 4 5 6 7 8 9 'Linux shell'
# The tenth parameter is Linux shell!

获取脚本名

虽然$0可以获取脚本名,但是有两个问题,一是命令会出现在$0中,比如脚本int.sh,在$0却是./int.sh,多了./,这不是我们想要的;还有就是,当指定脚本的路径时,$0也会完整保存路径和脚本名。

比如:bash /home/yan/LearningPerl/int.sh$0保存/home/yan/LearningPerl/int.sh,而不是int.sh,很多时候,我们只需要int.sh就行了,而不想要.//home/yan/LearningPerl/这些附属的字符。

幸运的是,有个basename命令可以很轻松的去除这些附属字符,只留下脚本名

bash 复制代码
#!/bin/bash
echo "The basename is $(basename $0)!"

这样,无论是./int.sh还是bash /home/yan/LearningPerl/int.sh就只留下int.sh了,这样,在调用脚本的时候就非常方便了。

测试参数

有时候,脚本设定要求提供参数,而实际中未提供时,会发生语法错误而导致程序崩溃,为了避免这种情况,就需要判断/测试是否提供了相应的参数给脚本使用。

-n用于测试参数。

bash 复制代码
#!/bin/bash
if test -n "$1"; then
	for line in $( cat $1)
	do
		echo $line | grep -Eo '\(\w+\)'
	done
else
	echo "Please provide your file to iterate!"
fi

统计参数的个数

特殊变量$#储存有命令行提供的参数的个数。获取最后一个命令行参数 ,需要特别的写法${!#}

bash 复制代码
#!/bin/bash
params=$#
echo The number of parameters is $params
echo The last parameter is ${!#}
bash 复制代码
./int.sh a b c

输出:

bash 复制代码
The number of parameters is 3
The last parameter is c

在这里,可以清楚的看到$#!#的区别。获取第 10 命令行参数时,需要用花括号圈起来,如:${10}

还有一种特殊情况,就是没有参数传入时,$#为 0 可以理解,但是${!#}会返回脚本名。

bash 复制代码
./int.sh

输出:

bash 复制代码
The number of parameters is 0
The last parameter is ./int.sh
bash 复制代码
bash /home/yan/LearningPerl/int.sh

输出:

bash 复制代码
The number of parameters is 0
The last parameter is /home/yan/LearningPerl/int.sh

遍历命令行所有参数

bash shell 里面有两个特殊变量,储存命令行的所有参数,但是这两个特殊变量又稍有不同。

bash 复制代码
./int.sh fred dino barney

$*

这个变量会将所有命令行参数当成一个整体对待,这个整体有所有的命令行参数。

bash 复制代码
#!/bin/bash
for param in "$*"
do
	echo "\$* parameter is $param"
done
# $* parameter is fred dino barney

$@

这个变量会将每一个的命令行参数当成一个个独立的单词,这样可以用 for 循环遍历所有的参数。

bash 复制代码
#!/bin/bash
for param in "$@"
do
	echo "\$* parameter is $param"
done
# $* parameter is fred
# $* parameter is dino
# $* parameter is barney

有个好的方法记住这一特性,那就是在Perl里面@表示数组,自然而然地就会想到能迭代了。

shift 移动参数

shift的功能是将左边第一个参数弹出,而后参数顺移补上。先来看一个简单的例子了解其工作原理:

bash 复制代码
./int.sh fred dino barney
bash 复制代码
#!/bin/bash
echo "$*"
shift
echo "$*"
# fred dino barney
# dino barney

第一个echo打印了所有的参数,而第二个echo删除了最左边的 fred,这就是shift 的工作原理。原先$1是 fred,shift 之后的$1顺移变成了 dino,所以在使用 shift 后要牢记参数位置发生的变化。

shift 命令默认删除最左边的第一个参数(也就是shift 1是默认的),也可以指定数字来删几个位置的参数。

bash 复制代码
#!/bin/bash
echo "$*"
shift 2
echo "$*"
echo $1
# fred dino barney
# barney
# barney

shift 2表示删除了最左边的两个参数,现在只剩最后一个参数了,相应的,$1也变成了 barney。

命令行选项

之前一直把命令行参数和选项搞混了,现在再来重新确定一下命令行参数和选项的区别。

为了区分选项和参数,Linux 特意将选项设置为单破折线后面跟一个字母,而参数则不需要单破折线。

例如:./int.sh -a sample,在这里,-a是选项,sample是参数。

要想写出一个鲁棒性强的脚本,必须兼顾各种情况,而选项恰恰是提供这种鲁棒性的工具。

  1. 首先,需要区分是选项还是参数?

    这部分内容的实现,需要一个判断语句case ,配合之前的shift 命令,结合while循环进行判断。

bash 复制代码
#!/bin/bash
while test -n "$1"
do
	case "$1" in
		-a) echo "-a is a option" ;;
		-b) echo "-b is a option" ;;
		-c) echo "-c is a option" ;;
		 *) echo "$1 is not a option" ;;
	esac
	shift
done

这样就能识别出特定的选项了。

  1. 区分选项和参数

    之所以要区分选项和参数,原因是没有必要遍历所有的命令行选项和参数,你把所有的命令行选项和参数遍历了一遍,shift命令就将所有的输入删除殆尽了,你要想调用参数已经被删除掉了,这种为了判断选项而遍历所有的输入不值当。换句话说,对于选项而言,我只需要遍历和判断选项,剩下的都当作参数处理。

    来看一个具体的例子就知道上面说的啥意思了:

bash 复制代码
#!/bin/bash
while test -n "$1"
do
	case "$1" in
		-a) echo "-a is a option" ;;
		-b) echo "-b is a option" ;;
		 *) echo "$1 is not a option" ;;
	esac
	shift
done

for var in "$@"
do
	echo "opening file $var"
done

./int.sh -a -b -c fred dino barney输出:

bash 复制代码
-a is a option
-b is a option
-c is not a option
fred is not a option
dino is not a option
barney is not a option

可以看到,后面的 fred、dino 和 barney 文件并没有被输出。这就是没有区别选项和参数的局限所在了。参数都被删除完了,后面想迭代已经没有了。

在 Linux 中,通常使用双破折线--来界定选项和参数。这样分开的好处是,可以及时打破循环,只对选项进行迭代,终止迭代参数,这样在后面的命令在就可以继续使用参数了,来看例子:

bash 复制代码
#!/bin/bash
while test -n "$1"
do
	case "$1" in
		-a) echo "-a is a option" ;;
		-b) echo "-b is a option" ;;
		--) shift
			break ;;
		 *) echo "$1 is not a option" ;;
	esac
	shift
done

for var in "$@"
do
	echo "opening file $var"
done

./int.sh -a -b -c -- fred dino barney输出:

bash 复制代码
-a is a option
-b is a option
-c is not a option
opening file fred
opening file dino
opening file barney

这个就是选项和参数分开的妙处。

  1. 处理带值的选项

    这要是选项和参数完全分开没啥问题,但是现实是有的选项带有值,这时候就需要针对带值的选项进行特殊处理。

bash 复制代码
#!/bin/bash
while test -n "$1"
do
	case "$1" in
		-a) echo "-a is a option" ;;
		-b) value="$2"
			echo "-b is a option with a value '$value'" ;;
		--) shift
			break ;;
		 *) echo "$1 is not a option" ;;
	esac
	shift
done

for param in "$@"
do
	echo "opening a file $param"
done

./int.sh -a -b today -c -- fred dino barney,现在-b选项带有值today,来看输出结果:

bash 复制代码
-a is a option
-b is a option with a value 'today'
today is not a option
-c is not a option
opening a file fred
opening a file dino
opening a file barney

有点小问题,就是today值不应该被判断为选项而打印出来,这时需要将其shift删除掉。

bash 复制代码
#!/bin/bash
while test -n "$1"
do
	case "$1" in
		-a) echo "-a is a option" ;;
		-b) value="$2"
			echo "-b is a option with a value '$value'"
			shift ;;
		--) shift
			break ;;
		 *) echo "$1 is not a option" ;;
	esac
	shift
done

for param in "$@"
do
	echo "opening a file $param"
done

./int.sh -a -b today -c -- fred dino barney,再来看输出结果:

bash 复制代码
-a is a option
-b is a option with a value 'today'
-c is not a option
opening a file fred
opening a file dino
opening a file barney

这次就完美了,非常符合预期结果,既个性化处理了带值的选项,同时也能对参数进行处理。

基于shift 命令的特性,每次读取后就将其删除,所以,只要带值的选项格式是:选项+值(例如本例中-b today),无论无何变换位置(如:-b today -a -c-c -a -b today等),都不影响处理带值的选项,但是不能把选项及其值分开(如本例:``-b -a today -c`这样的不行)。

需要强调的是:不管按什么顺序位置放置选项,都必须将带值的选项当作一个整体放置,程序都能正常运行。

./int.sh -b today -c -a -- fred dino barney

bash 复制代码
-b is a option with a value 'today'
-c is not a option
-a is a option
opening a file fred
opening a file dino
opening a file barney
  1. 处理合并选项

    现实中有许多人喜欢将选项合并写,这样可以省去键入的次数,但是以上所学还不足以实现选项的合并处理,这时需要使用getopt命令来帮助实现这一需求。

    getopt 命令的用法:getopt optstring parameters

    来看具体例子(选项不带值):

bash 复制代码
getopt abc -a -b -c fred dino barney
# -a -b -c -- fred dino barbey

选项带值:

bash 复制代码
getopt a:bc -a value1 -b -c fred dino barney
# -a value1 -b -c -- fred dino barbey
bash 复制代码
getopt a:b:c -a value1 -b value2 -c fred dino barney
# -a value1 -b value2 -c -- fred dino barbey
bash 复制代码
getopt a:b::c -a value1 -b value2 value3 -c fred dino barney
# -a value1 -b  -c -- value2 value3 fred dino barbey
bash 复制代码
getopt a:b::c -a value1 -b value2 -c fred dino barbey
# -a value1 -b  -c -- value2 fred dino barbey
bash 复制代码
getopt a:b:c -a value1 -b value2 value3 -c fred dino barbey
# -a value1 -b value2 -c -- value3 fred dino barbey
bash 复制代码
getopt a:bc -bc -a value1 fred dino barbey
# -b -c -a value1 -- fred dino barbey
bash 复制代码
getopt a:b:c -bc -a value1 fred dino barbey
# -b c -a value1 -- fred dino barbey

从以上例子可以看出,optstring先是定义了所要的选项,这些例子中是 a、b 和 c,如果某个选项带有值,则在其后面加上冒号:,选项不能带有多个值,也不能写两个冒号及以上表示多个值,只能由一个冒号表示一个值,否则结果将不符合预期。所以,安全起见,就一个冒号一个值吧。

再来说说getopt 命令的运行原理,首先,我们将getopt命令分为三个部分。

bash 复制代码
getopt a:bc -a value1 -bc fred dino barney
|----| |--| |------------------------------|
  ⬇      ⬇                 ⬇
getopt optstring       parameters

当其运行时,getopt 命令会检查parameters部分,并基于提供的optstring部分进行配对解析(顺序不影响其配对解析),当有合并的选项时(如这里的-bc),它会自动将其分成单独的两个选项,并用双破折线将选项和参数分开。

optstring部分有选项,而parameters部分没有时,会显示错误信息:

bash 复制代码
getopt a:bc -a value1 -bcd fred dino barney
# getopt: invalid option -- 'd'
# -a value1 -b -c -- fred dino barney

getopt 命令的-q选项可以忽略这条消息,并同时给选项值和参数加上单引号:

bash 复制代码
getopt -q a:bc -a value1 -bcd fred dino barney
# -a 'value1' -b -c -- 'fred' 'dino' 'barney'

现在,就可以在脚本中实现选项的合并了。

bash 复制代码
#!/bin/bash
set -- $(getopt -q ab:c "$@")
while test -n "$1"
do
	case "$1" in
		-a) echo "-a is a option" ;;
		-b) value="$2"
			echo "-b is a option with a value '$value'"
			shift ;;
		-c) echo "-c is a option" ;;
		--) shift
			break ;;
		 *) echo "$1 is not a option" ;;
	esac
	shift
done

for param in "$@"
do
	echo "opening a file $param"
done

./int.sh -ac -b value fred dino

bash 复制代码
-a is a option
-c is a option
-b is a option with a value ''value''
opening a file 'fred'
opening a file 'dino'

这样,即使合并选项,也能正常处理选项和参数,并且能够做到选项和参数分开各自处理,已经接近完美了,但是还是差一点点。就是它在处理带空格和引号的参数时有问题。

./int.sh -ac "fred dino" barney

bash 复制代码
-a is a option
-c is a option
opening a file 'fred
opening a file dino'
opening a file 'barney'

可以看出,并不能正确解析参数。要想解决这一问题,还得引入更加高级的getopts 命令

  1. 更高级的 getopts 命令

    getopts optstring variable

    去掉错误消息,需要在optstring前加冒号:,如getopts :abc

    那么,variable保存的是什么呢?来看一个例子就懂了

bash 复制代码
#!/bin/bash
while getopts :abc var
do
	echo "$var"
done

./int.sh -abcd输出:

bash 复制代码
a
b
c
?

由此可见,variable保存的是在 while 循环中每次迭代optstring的单个选项,如果optstring中没有,就以问号?表示。

此外,getopts命令有两个特殊变量:

  • OPTARG 变量

当选项带有值时,OPTARG 变量就保存这个选项的值。

./int.sh -a -b fred -c

bash 复制代码
while getopts :ab:c var
do
        echo "$var"
        echo "-b option have a value $OPTARG"
done

输出:

bash 复制代码
a
-b option have a value
b
-b option have a value fred
c
-b option have a value

OPTIND 变量

OPTIND 变量保存了 getopts 正在处理的参数位置。如果在循环体内,则 OPTARG 变量会随着循环迭代而增加,如果是在循环体外,则保存有最后一次处理选项的位置信息。选项的值也会被计入其中。

bash 复制代码
#!/bin/bash

while getopts :ab:c var
do
        echo "$var"
        echo "-b option have a value $OPTARG"
done
echo $OPTIND

输出:

bash 复制代码
a
-b option have a value
b
-b option have a value fred
c
-b option have a value
5

OPTIND 变量在循环体外,所以其保存了最后一次的选项位置,选项的值也被计入其中,而且,OPTIND 变量的值是位置上加 1,所以就成了 5,当我们需要 shift 选项时,则应在其基础上减 1 才符合实际。

另外需要注意的是,当合并键入选项时,会将那些合并的选项当成一个整体,然后在 OPTIND 变量中也相应的减少一,具体来看例子:

./int.sh -ab fred -c

bash 复制代码
a
-b option have a value
b
-b option have a value fred
c
-b option have a value
4

可以看到,尽管合并了选项,还是能正确解析出各个选项及其值,但是 OPTIND 变量变成 4 了,不是原来的 5 了。这么做也合理,你耐心看到后面就懂了。

getopts 命令在写法上也和 getopt 命令有所不同。

bash 复制代码
#!/bin/bash

while getopts :ab:c var
do
        case "$var" in
                a) echo "Found the -a option" ;;
                b) echo "Found the -b option, with a value $OPTARG" ;;
                c) echo "Found the -c option" ;;
                *) echo "Unknown option: $var" ;;
        esac
done
echo $OPTIND
shift $[ $OPTIND - 1 ]
echo
for param in "$@"
do
       echo "Parameter: $param"
done

./int.sh -ab today -c dino barney peter

输出:

bash 复制代码
Found the -a option
Found the -b option, with a value today
Found the -c option
4

Parameter: dino
Parameter: barney
Parameter: peter

./int.sh -a -b today -c dino barney peter

bash 复制代码
Found the -a option
Found the -b option, with value today
Found the -c option
5

Parameter: dino
Parameter: barney
Parameter: peter

case语句中没有了破折线,并且直接在 while 循环语言的判断式中调用 getopts 命令对选项参数列表进行循环。

正如上面所说的,OPTIND 变量不论是合并的选项,还是分开键入的选项,都能够很好的解析选项和参数,结合 shift 命令,如果是合并的选项,就将其一块计入 OPTIND 变量中,shift 命令也能将其一并删除,选项解析还是以 case 进行判断,真可谓妙啊。

getopts 命令还可以正确处理带空格和引号的参数,这就是 getopts 命令比较高级的地方。

bash 复制代码
#!/bin/bash
while getopts :ab:c opt
do
	case "opt" in
		a) echo "Input -a option, processing..." ;;
		b) echo "Input -b option with a value $OPTARG, processing..." ;;
		c) echo "Input -c option, processing..." ;;
		*) echo "Sorry, error input.."
	esac

done
echo
shift $[ $OPTIND - 1 ]
for param in "$@"
do
	echo "Proccessing the parameter $param"
done

./int.sh -a -b today -c "dino barney" fred

bash 复制代码
Input -a option, processing...
Input -b option with a value today, processing...
Input -c option, processing...

Proccessing the parameter dino barney
Proccessing the parameter fred

嗯,带双引号和空格的选项都能正常解析了,符合预期。

./int.sh -acb today "dino barney" fred./int.sh -ab today -c "dino barney" fred等等都能正常解析,但是一定要把 b 选项和 today 的顺序放一起,b 选项和 today 中间不能有别的值,如./int.sh -abc today "dino barney" fred这样就不能正常解析。

选项标准化

说人话就是,你自己创建 shell 脚本时,有权力去定义属于自己的脚本,选项可以按照自己的想法去定义,但是这样别人的学习成本就高了,将选项标准化的意思是将你的 shell 脚本写得更通俗普遍,而有些约定俗成的选项就不要去更改了,这样别人用起来也减少了学习成本,让你的脚本更容易被大众所接受,这就是选项标准化的实质。

已经约定俗成的选项代表的意义如下(部分例举):

  • -a 显示所有对象

  • -c 生成一个计数

  • -d 指定一个目录

  • -f 指定一个文件

  • -i 忽略文本大小写

  • -y 对所有问题回答 yes

获得输入(包括用户和文件的输入)

read命令接受来自标准键盘或文件的输入。

  • read 命令读取文件时,需要借助cat 命令和管道符,结合while 循环读取。别忘了,当退出码为零时while 循环继续,非零退出码时while终止。
bash 复制代码
#!/bin/bash
cat sample | while read line
do
	echo "$line"
done
  • read读取标准键盘输入。
bash 复制代码
#!/bin/bash
echo -n "Please enter your name: "
read name
echo "Hello, $name!"
bash 复制代码
#!/bin/bash
read -p "Please enter your name: " name
echo "Hello, $name!"

以上两个例子实现的效果一样,只是方式不同。

bash 复制代码
#!/bin/bash
read -p "Please enter your name and age: " name age
echo "Hi, $name, you are $age years old."

read命令会将输入分配给变量,如果输入与变量的数目一致,则变量得到对应位置的输入,如果变量的数量不够,剩下的输入数据就全部分配给最后的一个变量。

bash 复制代码
#!/bin/bash
read -p "Please enter your files: " fred dino barney
echo "here is the files your input: $fred $dino $barney "
bash 复制代码
Please enter your files: fred dino barney peter
here is the files your input: fred dino barney peter

Linux shell 中还有一个特殊的变量,REPLY 变量负责接收read 命令输入的数据。前提是将设定的变量删除,否则$REPLY内空无一物。

bash 复制代码
#!/bin/bash
read -p "Please enter your files: "
for file in $REPLY
do
        echo "Processing file: $file"
done

等待超时

read 命令-t选项来指定输入的时间,如果超过,规定时间,则终止输入并给予提示。

bash 复制代码
#!/bin/bash
if read -t 10 -p "Please enter your telephone whithin 10 seconds: ";
then
	echo
	echo "Your telephone number $REPLY has been saved."
else
	echo
	echo "Time out!"
fi

隐藏方式读取

-s选项可以避免将数据出现在显示器中,在输入密码时尤为合适。

bash 复制代码
#!/bin/bash
read -s  -p "Enter your password: " pass
if test $pass -eq '1234'; then
	echo
	echo "your password is correct!"
else
	echo
	echo "Sorry, It doesn't work!"
fi

现在,可以自己写 shell 脚本或 perl 脚本或 r 脚本,定义自己的选项和参数,创建一个鲁棒性强的脚本啦。

相关推荐
databook1 小时前
Manim实现闪光轨迹特效
后端·python·动效
Juchecar2 小时前
解惑:NumPy 中 ndarray.ndim 到底是什么?
python
用户8356290780512 小时前
Python 删除 Excel 工作表中的空白行列
后端·python
Json_2 小时前
使用python-fastApi框架开发一个学校宿舍管理系统-前后端分离项目
后端·python·fastapi
数据智能老司机9 小时前
精通 Python 设计模式——分布式系统模式
python·设计模式·架构
数据智能老司机10 小时前
精通 Python 设计模式——并发与异步模式
python·设计模式·编程语言
数据智能老司机10 小时前
精通 Python 设计模式——测试模式
python·设计模式·架构
数据智能老司机10 小时前
精通 Python 设计模式——性能模式
python·设计模式·架构
c8i10 小时前
drf初步梳理
python·django
每日AI新事件10 小时前
python的异步函数
python