Wyodrębnij parametry przed ostatnim parametrem w "$@"

Próbuję stworzyć skrypt Bash, który wyodrębni ostatni parametr podany z wiersza poleceń do zmiennej, która będzie używana gdzie indziej. Oto scenariusz, nad którym pracuję:

#!/bin/bash
# compact - archive and compact file/folder(s)

eval LAST=\$$#

FILES="$@"
NAME=$LAST

# Usage - display usage if no parameters are given
if [[ -z $NAME ]]; then
  echo "compact <file> <folder>... <compressed-name>.tar.gz"
  exit
fi

# Check if an archive name has been given
if [[ -f $NAME ]]; then
  echo "File exists or you forgot to enter a filename.  Exiting."
  exit
fi

tar -czvpf "$NAME".tar.gz $FILES

Ponieważ pierwsze parametry mogą być dowolnej liczby, muszę znaleźć sposób na wyodrębnienie ostatniego parametru (np. plik Kompaktowy.plik.plik B.d files-A-b-D. tar.gz). Jak to jest teraz nazwa archiwum będzie zawarte w plikach do kompaktu. Jest na to sposób?

Author: Tshepang, 2009-08-01

14 answers

Aby usunąć ostatni element z tablicy możesz użyć czegoś takiego:

#!/bin/bash

length=$(($#-1))
array=${@:1:$length}
echo $array
 85
Author: Krzysztof Klimonda,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-01 01:33:38
last_arg="${!#}" 
 18
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-01 09:28:03

Kilka rozwiązań zostało już opublikowanych, jednak radzę zrestrukturyzować skrypt tak, aby nazwa archiwum była parametrem first, a nie ostatnim. To jest naprawdę proste, ponieważ można użyć shift Wbudowany aby usunąć pierwszy parametr:

ARCHIVENAME="$1"
shift
# Now "$@" contains all of the arguments except for the first
 11
Author: Adam Rosenfield,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-01 21:55:14

Przenośne i kompaktowe rozwiązania

Tak robię w moich skryptach

last=${@:$#} # last parameter 
other=${*%${!#}} # all parameters except the last
Podoba mi się, ponieważ jest to bardzo kompaktowe rozwiązanie.
 9
Author: ePi272314,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-13 14:52:36

Thanks guys, got it done, heres the final bash script:

#!/bin/bash
# compact - archive and compress file/folder(s)

# Extract archive filename for variable
ARCHIVENAME="${!#}"

# Remove archive filename for file/folder list to backup
length=$(($#-1))
FILES=${@:1:$length} 

# Usage - display usage if no parameters are given
if [[ -z $@ ]]; then
  echo "compact <file> <folder>... <compressed-name>.tar.gz"
  exit
fi

# Tar the files, name archive after last file/folder if no name given
if [[ ! -f $ARCHIVENAME ]]; then
  tar -czvpf "$ARCHIVENAME".tar.gz $FILES; else
  tar -czvpf "$ARCHIVENAME".tar.gz "$@"
fi
 4
Author: user148813,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-01 21:36:31

Wystarczy zrzucić zmienną length zastosowaną w rozwiązaniu Krzysztofa Klimondy:

(
set -- 1 2 3 4 5
echo "${@:1:($#-1)}"       # 1 2 3 4
echo "${@:(-$#):($#-1)}"   # 1 2 3 4
)
 3
Author: bashist,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-06 17:47:27

Dodałbym to jako komentarz, ale nie mam wystarczającej reputacji, a odpowiedź i tak trochę się wydłużyła. Mam nadzieję, że to nie przeszkadza.

Jak stwierdził @ func:

Last_arg="${!#}"

Jak to działa:

${!PARAM} wskazuje poziom indrection. Nie odwołujesz się do samej PARAM, ale do wartości przechowywanej w PARAM ( pomyśl o PARAM jako wskaźniku do wartości ).
${#} rozszerza się do liczby parametry (Uwaga: $0 - Nazwa skryptu - nie jest tu liczona).

Rozważ następujące wykonanie:

$./myscript.sh p1 p2 p3

I w myscript.sh

#!/bin/bash

echo "Number of params: ${#}"  # 3
echo "Last parameter using '\${!#}': ${!#}"  # p3
echo "Last parameter by evaluating positional value: $(eval LASTP='$'${#} ; echo $LASTP)"  # p3

Stąd możesz myśleć o ${!#} jako skrót do powyższego zastosowania eval, które wykonuje dokładnie opisane powyżej podejście-oblicza wartość zapisaną w podanym parametrze, tutaj parametr jest 3 i utrzymuje argument pozycyjny$3

Teraz, jeśli chcesz wszystkie params oprócz ostatni, możesz użyć usuwania podłańcucha ${PARAM%PATTERN} gdzie % znak oznacza 'Usuń najkrótszy pasujący wzór z końca łańcucha' .

Stąd w naszym skrypcie:

echo "Every parameter except the last one: ${*%${!#}}"


Możesz tu coś przeczytać: rozszerzenie parametru

 3
Author: CermakM,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-25 08:46:13
#!/bin/bash

lastidx=$#
lastidx=`expr $lastidx - 1`

eval last='$'{$lastidx}
echo $last
 1
Author: jsight,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-01 01:23:56

Jesteś pewien, że ten wymyślny skrypt jest lepszy niż zwykły alias do tar?

alias compact="tar -czvpf"

Użycie to:

compact ARCHIVENAME FILES...

Gdzie pliki mogą być file1 file2 lub takie jak *.html

 1
Author: MestreLion,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-06 11:42:46

Try:

if [ "$#" -gt '0' ]; then
    /bin/echo "${!#}" "${@:1:$(($# - 1))}
fi
 1
Author: zorro,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-16 18:10:10
#!/bin/sh

eval last='$'$#
while test $# -gt 1; do
    list="$list $1"
    shift
done

echo $list $last

 0
Author: William Pursell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-01 01:20:19

Nie mogę znaleźć sposobu na użycie notacji array-subscript na $@, więc to jest najlepsze, co mogę zrobić:

#!/bin/bash

args=("$@")
echo "${args[$(($#-1))]}"
 0
Author: Norman Ramsey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-01 01:41:26

Ten skrypt może działać dla Ciebie-zwraca podzbiór argumentów i może być wywołany z innego skryptu.

Przykłady jego działania:

$ args_get_range 2 -2 y a b "c 1" d e f g                          
'b' 'c 1' 'd' 'e'

$ args_get_range 1 2 n arg1 arg2                                   
arg1 arg2

$ args_get_range 2 -2 y arg1 arg2 arg3 "arg 4" arg5                
'arg2' 'arg3'

$ args_get_range 2 -1 y arg1 arg2 arg3 "arg 4" arg5                
'arg2' 'arg3' 'arg 4'

# You could use this in another script of course 
# by calling it like so, which puts all
# args except the last one into a new variable
# called NEW_ARGS

NEW_ARGS=$(args_get_range 1 -1 y "$@")

Args_get_range.sh

#!/usr/bin/env bash

function show_help()
{
  IT="
  Extracts a range of arguments from passed in args
  and returns them quoted or not quoted.

  usage: START END QUOTED ARG1 {ARG2} ...

  e.g. 

  # extract args 2-3 
  $ args_get_range.sh 2 3 n arg1 arg2 arg3
  arg2 arg3

  # extract all args from 2 to one before the last argument 
  $ args_get_range.sh 2 -1 n arg1 arg2 arg3 arg4 arg5
  arg2 arg3 arg4

  # extract all args from 2 to 3, quoting them in the response
  $ args_get_range.sh 2 3 y arg1 arg2 arg3 arg4 arg5
  'arg2' 'arg3'

  # You could use this in another script of course 
  # by calling it like so, which puts all
  # args except the last one into a new variable
  # called NEW_ARGS

  NEW_ARGS=\$(args_get_range.sh 1 -1 \"\$@\")

  "
  echo "$IT"
  exit
}

if [ "$1" == "help" ]
then
  show_help
fi
if [ $# -lt 3 ]
then
  show_help
fi

START=$1
END=$2
QUOTED=$3
shift;
shift;
shift;

if [ $# -eq 0 ]
then
  echo "Please supply a folder name"
  exit;
fi

# If end is a negative, it means relative
# to the last argument.
if [ $END -lt 0 ]
then
  END=$(($#+$END))
fi

ARGS=""

COUNT=$(($START-1))
for i in "${@:$START}"
do
  COUNT=$((COUNT+1))

  if [ "$QUOTED" == "y" ]
  then
    ARGS="$ARGS '$i'"
  else
    ARGS="$ARGS $i"
  fi

  if [ $COUNT -eq $END ]
  then
    echo $ARGS
    exit;
  fi
done
echo $ARGS
 0
Author: Brad Parks,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-13 20:04:57

Tablica bez ostatniego parametru:

array=${@:1:$#-1}

Ale to jest bashism : (. Odpowiednie rozwiązania polegałyby na przesunięciu i dodaniu do zmiennej w miarę korzystania przez innych.

 0
Author: pevik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-24 05:04:56