如何在 shell 脚本中删除参数(从参数列表中)?

如何在 shell 脚本中删除参数(从参数列表中)?

我有以下(MWE)shell 脚本foo

#!/bin/bash
ARGS=("$@") # all arguments
## => if it exists, we need to drop the argument "-D" here
ls -l ${ARGS[@]} | sort -fk8 

如果foo使用参数调用-D(参数列表中的位置未知),我如何-D从参数列表中删除?例如,我发现unset ARGS[${#ARGS[@]}-1]可以删除最后一个参数,但我不确定参数的传递顺序(因此我首先需要知道参数在哪个位置,然后在提供参数时将其删除)。

答案1

简单的方法是简单地循环位置参数,将所有参数收集-D到一个数组中,然后用于set --更新参数:

for param; do 
    [[ ! $param == '-D' ]] && newparams+=("$param")
done
set -- "${newparams[@]}"  # overwrites the original positional params

答案2

对于zsh,使用${array:#pattern}参数扩展运算符:

$ set foo -D -D bar '' $'a\nb'
$ printf '<%s>\n' "${@:#-D}"
<foo>
<bar>
<>
<a
b>

POSIXly:

for i do
  [ "$i" = -D ] || set -- "$@" "$i"
  shift
done
printf '<%s>\n' "$@"

顺便说一句,你忘记了引号,--并且-d

ls -ld -- "$@"

如果你想按修改时间排序,你可以使用该-t选项,这里使用-r(reverse) 表示最早的在前:

ls -lrtd -- "$@"

请注意,如果$ARGS是一个空数组,它将列出.。所以你可以这样做:

[ "$@" -eq 0 ] || ls -lrtd -- "$@"

排序可靠地基于一天中的小时而不考虑日期,并且zsh支持ls-U排序的实现:

zmodload zsh/stat # best in ~/.zshrc
bytime() zstat -LA REPLY -F%T  +mtime -- $REPLY
ls --full-time  -ldU -- .(e{'reply=("$@")'}o+bytime)

对于像 这样的有限 shell bash,很难根据这样的任意元数据对文件进行排序。再说一遍,如果您可以访问最新的 GNU 工具,那就稍微容易一些:

[ "$#" -gt 0 ] && (
  export LC_ALL=C
  printf '%s\0' "$@" |
    sed -z 's|^-$|./-|' |
    xargs -r0 stat --printf '%y\t%n\0' -- |
    sort -zk2,2 |
    cut -zf 2-
) | xargs -r0 ls -lUd --

可移植(但仍然使用非标准ls -U),通常更容易求助于perl,例如:

perl -MPOSIX -e '
  exec qw{ls -ldU --}, 
    map {$_->[1]}
    sort {$a->[0] cmp $b->[0]}
    map {[strftime("%T", localtime((lstat$_)[9])), $_]}
    @ARGV' -- "$@"

相关内容