我正在编写一个 bash 脚本,该脚本从命令行参数读取目录并ls
对其执行操作。
如果我指定一个简单的目录,那么一切都可以。
但我想做类似的事情/home/{x,y}
,所以脚本的调用是my-script -d '/home/{x,y}'
的值'/home/{x,y}'
存储在名为 的变量中source
。
我尝试过
ls "${source}"
,但它返回ls: cannot access /home/{x,y}: No such file or directory
我尝试过
ls ${!source}
,但它返回当前目录中的文件。我尝试过
ls \$$source
,但再次失败并出现第一个错误。
如何扩展'/home/{x,y}'
脚本中的参数以便它运行ls /home/x /home/y
?
答案1
通常的方法是将目录作为主命令行参数传递,而不需要选项标志。即用户将运行my-script -a -b foo /home/me/dir1 /some/other/path
.运行解析选项后getopts
,您将保留位置参数中的目录,并且可以运行ls "$@"
.在这里,用户可以使用 shell 允许他们填充的任何扩展来填充最后的参数,无论是/some/path/{foo,bar}
,还是/some/path/*
。
或者,让用户传递多个-d
选项,以便他们运行my-script -a -b foo -d /home/me/dir1 -d /some/other/path
.在这里,使用扩展比较困难,因为他们需要-d
在每个参数前面添加 shell 允许的任何内容。也许有类似的东西a=(/path/{this,that}); my-script -a -b foo "${a[@]/#/-d}"
。
无论如何,在脚本中复制 shell 的扩展并不常见,而且可能会让用户措手不及,因此我建议不要这样做。如果您这样做,您还需要决定哪个扩展以支持。并非所有 shell 都支持所有扩展,也并非所有用户都知道每个 shell 支持的所有扩展。
答案2
示例.sh:
#!/usr/bin/env bash
FILE_PATTERN="$1"
MATCHING_FILES=$(eval "echo $FILE_PATTERN")
echo "Files: $MATCHING_FILES"
ls -l $MATCHING_FILES
这将使用 example.sh 的第一个参数作为 shell glob 模式。它可能会破坏包含空格或特殊字符的文件名。如何引用变量以避免这种情况,同时仍然应用该模式有待您找出。
用法:
$ ./example.sh 'file-{x,y}.txt'
Files: file-x.txt file-y.txt
-rw-r--r-- 1 user group 0 30 Sep 16:47 file-x.txt
-rw-r--r-- 1 user group 0 30 Sep 16:47 file-y.txt
如果可以的话,最好是不是执行此操作并接受多个文件名作为参数。它肯定会使变量引用更加清晰和容易,并且您可以避免处理 Stéphane 提出的关于看起来像 glob 模式的文件名的问题。
答案3
我会做:
#! /bin/bash -
sources=()
while getopts d:... o; do
case $o in
(d) sources+=("$OPTARG");;
(...) ;;
esac
done
shift "$((OPTIND - 1))"
ls -- "${sources[@]}"
也就是说,让您的脚本获取目录列表,其中调用者-d
对每个目录使用一个目录。
然后用户可以执行以下操作:
my-script -d/home/{x,y}
如果他们的 shell 支持大括号扩展,或者他们的 shell 提供了任何有助于构建该列表的功能。
在rc
//中fish
,zsh -o rcexpandparam
可以是:
my-script -d$array
例如(也-d$^array
没有rcexpandparam
in zsh
)
在zsh
:
my-script /home/*(P[-d])
ETC。
为了让您的脚本对参数执行大括号扩展而不是其他形式的扩展,您可以引用除{
, }
and之外的所有字符序列,
(.0-9
如果您想允许{1..10}
样式字符),然后运行它eval
。
zsh
使用or会更容易,ksh93
因为bash
's${var//pattern/replacement}
非常有限:
#! /bin/zsh -
source=${1?}
set -o extendedglob
eval "sources=( ${source//(#m)[^"{}".,0-9]##/'$MATCH'} )"
printf ' - "%s"\n' "$sources[@]"
例子:
$ myscript 'x\{1..3}$$`{a b,c}'
- "x\1$$`a b"
- "x\1$$`c"
- "x\2$$`a b"
- "x\2$$`c"
- "x\3$$`a b"
- "x\3$$`c"
但随后,用户将无法再传递文字foo{a,b}
参数。
答案4
发生这种情况是因为它被评估为多个参数而不是一个。尝试这个:
ls "$@"
$@
将所有参数扩展为空格分隔的字符串。