Como eliminar um argumento (da lista de argumentos) em um script de shell?

0

Eu tenho o seguinte script de shell (MWE) foo :

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

Se foo for chamado com argumento -D (a posição na lista de argumentos é desconhecida), como posso remover -D da lista de argumentos? Descobri que unset ARGS[${#ARGS[@]}-1] pode eliminar o último argumento, por exemplo, mas não tenho certeza em qual ordem os argumentos foram passados (portanto, primeiro preciso saber em qual lugar o argumento está e, em seguida, removê-lo, caso seja forneceu).

    
por Marius Hofert 11.11.2017 / 12:39

2 respostas

3

A abordagem sem frescuras é simplesmente percorrer os parâmetros posicionais, coletando todos, menos -D em uma matriz e, em seguida, usar set -- para atualizar os parâmetros:

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

Com zsh , use o operador de expansão de parâmetro ${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' "$@"

BTW, você esqueceu as citações, -- e -d :

ls -ld -- "$@"

Se você quiser ordenar por tempo de modificação, basta usar a opção -t , aqui com -r (reverso) para o mais antigo primeiro:

ls -lrtd -- "$@"

Tenha em atenção que, se $ARGS for uma matriz vazia, listará . . Então você pode fazer:

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

Para classificar confiavelmente com base na hora do dia, independentemente da data, com zsh e uma ls implementação que suporta -U para não classificar:

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

Com shells limitados como bash , é muito difícil classificar arquivos com base em metadados arbitrários como esse. Novamente, se você tiver acesso a ferramentas GNU recentes, será um pouco mais fácil:

[ "$#" -gt 0 ] && (
  export LC_ALL=C
  printf '%s
perl -MPOSIX -e '
  exec qw{ls -ldU --}, 
    map {$_->[1]}
    sort {$a->[0] cmp $b->[0]}
    map {[strftime("%T", localtime((lstat$_)[9])), $_]}
    @ARGV' -- "$@"
' "$@" | sed -z 's|^-$|./-|' | xargs -r0 stat --printf '%y\t%n
$ set foo -D -D bar '' $'a\nb'
$ printf '<%s>\n' "${@:#-D}"
<foo>
<bar>
<>
<a
b>
' -- | sort -zk2,2 | cut -zf 2- ) | xargs -r0 ls -lUd --

Portável (mas ainda usando o não-padrão ls -U aqui), geralmente é mais fácil recorrer a perl , como:

for i do
  [ "$i" = -D ] || set -- "$@" "$i"
  shift
done
printf '<%s>\n' "$@"
    
por 11.11.2017 / 13:18