如何编写接受来自文件或标准输入的输入的脚本?

gil*_*och 68 bash command-line stdin

如何编写一个脚本来接受来自文件名参数或标准输入的输入?

例如,您可以使用less这种方式。一个可以执行less filename和等效cat filename | less

有没有一种简单的“开箱即用”的方式来做到这一点?还是我需要重新发明轮子并在脚本中编写一些逻辑?

sus*_*tus 68

如果 file 参数是脚本的第一个参数,请测试是否有参数 ( $1) 并且它是一个文件。否则从标准输入读取输入 -

所以你的脚本可能包含这样的内容:

#!/bin/bash
[ $# -ge 1 -a -f "$1" ] && input="$1" || input="-"
cat $input
Run Code Online (Sandbox Code Playgroud)

例如,那么你可以像这样调用脚本

./myscript.sh filename
Run Code Online (Sandbox Code Playgroud)

或者

who | ./myscript.sh
Run Code Online (Sandbox Code Playgroud)

编辑 脚本的一些解释:

[ $# -ge 1 -a -f "$1" ]- 如果至少有一个命令行参数 ( $# -ge 1) AND (-a operator) 第一个参数是一个文件(-f 测试“$1”是否是一个文件),那么测试结果为真。

&&是 shell 逻辑 AND 运算符。如果测试为真,则分配input="$1"cat $input输出文件。

||是外壳逻辑 OR 运算符。如果测试为假,则||解析以下命令。输入分配给“-”。该命令cat -从键盘读取。

总而言之,如果提供了 script 参数并且它是一个文件,那么变量 input 将分配给文件名。如果没有有效参数,则 cat 从键盘读取。


小智 13

read从标准输入读取。从文件 ( ./script <someinput) 或通过管道 ( dosomething | ./script)重定向它不会使其工作方式不同。

您所要做的就是遍历输入中的所有行(这与遍历文件中的行没有区别)。

(示例代码,只处理一行)

#!/bin/bash

read var
echo $var
Run Code Online (Sandbox Code Playgroud)

将回显标准输入的第一行(通过<|)。


小智 5

你没有提到你打算使用什么 shell,所以我会假设 bash,尽管这些都是 shell 中非常标准的东西。

文件参数

可以通过变量访问参数$1- $n$0返回用于运行程序的命令)。假设我有一个脚本,它只cat输出 n 个文件,它们之间有一个分隔符:

#!/usr/bin/env bash
#
# Parameters:
#    1:   string delimiter between arguments 2-n
#    2-n: file(s) to cat out
for arg in ${@:2} # $@ is the array of arguments, ${@:2} slices it starting at 2.
do
   cat $arg
   echo $1
done
Run Code Online (Sandbox Code Playgroud)

在这种情况下,我们将文件名传递给 cat。但是,如果您想转换文件中的数据(无需明确写入和重写),您还可以将文件内容存储在变量中:

file_contents=$(cat $filename)
[...do some stuff...]
echo $file_contents >> $new_filename
Run Code Online (Sandbox Code Playgroud)

从标准输入读取

就从 stdin 读取而言,大多数 shell 都有一个非常标准的read内置函数,尽管在指定提示的方式上存在差异(至少)。

猛砸内建手册页有一个非常简明的解释read,但我更喜欢猛砸黑客网页。

简单地:

read var_name
Run Code Online (Sandbox Code Playgroud)

多个变量

要设置多个变量,只需提供多个参数名称即可read

read var1 var2 var3
Run Code Online (Sandbox Code Playgroud)

read 然后将 stdin 中的一个单词放入每个变量中,将所有剩余的单词转储到最后一个变量中。

? read var1 var2 var3
thing1 thing2 thing3 thing4 thing5
? echo $var1; echo $var2; echo $var3
thing1
thing2
thing3 thing4 thing5
Run Code Online (Sandbox Code Playgroud)

如果输入的单词少于变量,则剩余的变量将为空(即使之前已设置):

? read var1 var2 var3
thing1 thing2
? echo $var1; echo $var2; echo $var3
thing1
thing2
# Empty line
Run Code Online (Sandbox Code Playgroud)

提示

-p经常使用标志来提示:

read -p "Enter filename: " filename
Run Code Online (Sandbox Code Playgroud)

注意:ZSH 和 KSH(可能还有其他)使用不同的提示语法:

read "filename?Enter filename: " # Everything following the '?' is the prompt
Run Code Online (Sandbox Code Playgroud)

默认值

这并不是真正的read技巧,但我经常将它与read. 例如:

read -p "Y/[N]: " reply
reply=${reply:-N}
Run Code Online (Sandbox Code Playgroud)

基本上,如果变量(reply)存在,则返回自身,但如果是空的,则返回以下参数(“N”)。