如何在Linux终端使用命令将文件参数传递给我的bash脚本?

59

我的问题是如何在Linux终端命令中传递文件参数给我的Bash脚本?目前我正在尝试编写一个Bash程序,可以从终端获取文件参数,并将其用作程序中的变量。例如,在终端中运行myprogram --file=/path/to/file

我的程序

#!/bin/bash    
File=(the path from the argument)  
externalprogram $File (other parameters)

我如何在我的程序中实现这个?

4个回答

79

如果你直接以以下方式运行脚本,会更加容易(并且更"规范",请参见下文)

myprogram /path/to/file

然后你可以在脚本中通过 $1(代表第一个参数,类似地,$2 代表第二个参数,以此类推)来访问该路径。

file="$1"
externalprogram "$file" [other parameters]
或者只需
externalprogram "$1" [otherparameters]

如果你想从类似于--file=/path/to/file的东西中提取路径,通常使用getopts shell函数来完成。但这比简单引用$1要复杂得多,并且像--file=这样的开关是可选的。我猜你的脚本需要提供一个文件名,因此在一个选项中传递它是没有意义的。


4
请注意,所有参数扩展都需要加引号,包括 $file - Philipp
2
通常情况下,您只需检查用户是否提供了文件名(参数包含位置参数的数量),如果没有给出文件或-,则使用标准输入。如果您想要使用--file =语法,请使用case语句。 - Philipp
文件名中有空格会发生什么? - chovy
如果不加引号,Bash 会根据空格将其拆分成多个单词。例如,如果文件名为 test file.txt 并且您运行 externalprogram $file,外部程序将看到两个参数:“test”和“file.txt”,但是如果您运行 externalprogram "$file",它将看到一个参数,“test file.txt”。 - David Z
我只需要引用它 file="$1" - chovy
显示剩余2条评论

25

你可以使用getopt处理bash脚本中的参数。目前关于getopt的解释并不多。以下是一个例子:

#!/bin/sh

OPTIONS=$(getopt -o hf:gb -l help,file:,foo,bar -- "$@")

if [ $? -ne 0 ]; then
  echo "getopt error"
  exit 1
fi

eval set -- $OPTIONS

while true; do
  case "$1" in
    -h|--help) HELP=1 ;;
    -f|--file) FILE="$2" ; shift ;;
    -g|--foo)  FOO=1 ;;
    -b|--bar)  BAR=1 ;;
    --)        shift ; break ;;
    *)         echo "unknown option: $1" ; exit 1 ;;
  esac
  shift
done

if [ $# -ne 0 ]; then
  echo "unknown option(s): $@"
  exit 1
fi

echo "help: $HELP"
echo "file: $FILE"
echo "foo: $FOO"
echo "bar: $BAR"

参见:

链接失效。以下为互联网档案馆中的链接:


16

Bash支持名为"位置参数"的概念。这些位置参数代表在调用Bash脚本时在命令行上指定的参数。

位置参数由名称$0$1$2等表示,其中$0是脚本本身的名称,$1是脚本的第一个参数,$2是第二个参数,依此类推。$*代表除了$0(即从$1开始)外的所有位置参数。

例如:

#!/bin/bash
FILE="$1"
externalprogram "$FILE" <other-parameters>

2
是的,你说得对,在这种情况下,我们期望$1包含一个文件名,它应该被引用以避免单词拆分,如果文件名包含一个或多个空格。但是,引用位置参数 总是 必要的吗? - Dan Moulding
我认为始终将所有变量加引号比猜测它们是否需要引号更容易。位置参数是用户输入,用户可以输入任何内容,因此,除非有记录表明参数要经过单词拆分,否则必须加引号。从技术上讲,在“=”后面和“[[...]]”内部不必引用变量,但再次引用它们比记住哪里不执行单词拆分更容易。 - Philipp
@Philipp:好观点。谢谢! - Dan Moulding

2
假设您按照David Zaslavsky的建议执行,使第一个参数只是要运行的程序(不需要解析选项),那么您需要处理如何将第2个及之后的参数传递给外部程序的问题。这里有一种方便的方法:
#!/bin/bash
ext_program="$1"
shift
"$ext_program" "$@"
shift命令将删除第一个参数,并将剩余的参数重命名($2变成了$1,以此类推)。$@指代参数作为一个单词数组(它必须被引用!)。
如果你一定要使用--file语法(例如,如果有默认程序可运行,因此用户不一定需要提供),只需将ext_program="$1"替换为您需要执行的$1解析,可能使用getopt或getopts。
如果您想要为仅一个特定情况打造自己的代码,可以做如下处理:
if [ "$#" -gt 0 -a "${1:0:6}" == "--file" ]; then
    ext_program="${1:7}"
else
    ext_program="default program"
fi

"+1" for quoting. 但是,无论是 getopt 还是 getopts 都无法解析 GNU 样式的参数。 - Philipp
@Philipp:getopts不行,但是getopt肯定可以,在我的系统上是这样的。可能是因为C函数getopt有GNU和非GNU版本的原因。 - Cascabel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接