Функция удара, которая берет аргумент как другие языки?

Просто извлечение содержания архива не установит Ваше программное обеспечение. Проверьте папку, где Вы извлекли файлы, там будут инструкции по установке.

Можно также попытаться после этого руководства создать debian пакет из архива tar.gz.

Наконец, jdk1.7 находится в "экспериментальном" репозитории Debian. Можно отредактировать /etc/apt/sources.lst включать эту строку:

deb http://ftp.debian.org/debian experimental main

Затем выполните эти команды:

sudo apt-get update
sudo apt-get install default-jdk

ПРЕДУПРЕЖДЕНИЕ: В зависимости от того, насколько актуальный Ваша система, много пакетов, возможно, должны были бы быть обновлены, который мог привести к нестабильной системе. Удостоверьтесь, что Вы изменяете Ваш /etc/apt/sources.lst назад к тому, как это было прежде при выборе этого метода.

17
02.04.2014, 00:26
9 ответов

В bash вы можете использовать $ {! Varname} для расширения переменной, на которую ссылается содержимое другой переменной. Например:

$ var=hello
$ foo () { echo "${!1}"; }
$ foo var
hello

На странице руководства:

${!prefix*}
${!prefix@}
       Names matching prefix.  Expands to the names of variables whose names
       begin with prefix, separated by the first character of the IFS special
       variable.  When @ is used  and the expansion appears within double quotes,
       each variable name expands to a separate word.

Кроме того, чтобы установить переменную, на которую ссылается содержимое (без опасностей eval ), вы можете использовать declare . Например:

$ var=target
$ declare "$var=hello"
$ echo "$target"
hello

Таким образом, вы можете написать свою функцию так (будьте осторожны, потому что если вы используете declare в функции, вы должны указать -g , иначе переменная будет локальной) :

shopt -s extglob

assign()
{
  target=$1
  bigstr=${!1}
  substr=$2

  if [ -z "$bigstr" ]; then
    declare -g -- "$target=$substr"
  elif [[ $bigstr != @(|*:)$substr@(|:*) ]]; then
    declare -g -- "$target=$bigstr:$substr"
  fi
}

И используйте это как:

assign PATH /path/to/binaries

Обратите внимание, что я также исправил ошибку, когда if substr уже является подстрокой одного из разделенных двоеточием членов bigstr , но не его собственный член, тогда он не будет добавлен. Например, это позволит добавить / bin к переменной PATH , уже содержащей / usr / bin . Он использует наборы extglob для сопоставления либо начала / конца строки, либо двоеточия, а затем чего-либо еще. Без extglob альтернативой будет:

[[ $bigstr != $substr && $bigstr != *:$substr &&
   $bigstr != $substr:* && $bigstr != *:$substr:* ]]
17
27.01.2020, 19:46

Новым в bash 4.3 является опция -n для объявления & local :

func() {
    local -n ref="$1"
    ref="hello, world"
}

var='goodbye world'
func var
echo "$var"

Это распечатывает привет, мир .

9
27.01.2020, 19:46

С помощью нескольких трюков вы можете фактически передать именованные параметры в функции, наряду с массивами (тестировались на bash 3 и 4).

Метод, который я разработал, позволяет получить доступ к параметрам, передаваемым в такую функцию:

testPassingParams() {

    @var hello
    l=4 @array anArrayWithFourElements
    l=2 @array anotherArrayWithTwo
    @var anotherSingle
    @reference table   # references only work in bash >=4.3
    @params anArrayOfVariedSize

    test "$hello" = "$1" && echo correct
    #
    test "${anArrayWithFourElements[0]}" = "$2" && echo correct
    test "${anArrayWithFourElements[1]}" = "$3" && echo correct
    test "${anArrayWithFourElements[2]}" = "$4" && echo correct
    # etc...
    #
    test "${anotherArrayWithTwo[0]}" = "$6" && echo correct
    test "${anotherArrayWithTwo[1]}" = "$7" && echo correct
    #
    test "$anotherSingle" = "$8" && echo correct
    #
    test "${table[test]}" = "works"
    table[inside]="adding a new value"
    #
    # I'm using * just in this example:
    test "${anArrayOfVariedSize[*]}" = "${*:10}" && echo correct
}

fourElements=( a1 a2 "a3 with spaces" a4 )
twoElements=( b1 b2 )
declare -A assocArray
assocArray[test]="works"

testPassingParams "first" "${fourElements[@]}" "${twoElements[@]}" "single with spaces" assocArray "and more... " "even more..."

test "${assocArray[inside]}" = "adding a new value"

Другими словами, вы можете не только вызывать свои параметры по их именам (что составляет более читабельное ядро), но и фактически передавать массивы (а ссылки на переменные - эта функция работает только в bash 4.3)! Кроме того, все отображенные переменные находятся в локальной области видимости, всего $1 (и другие).

Код, который делает эту работу довольно легкой и работает как на bash 3, так и на bash 4 (это единственные версии, с которыми я его тестировал). Если вас интересуют такие трюки, как этот, которые делают разработку с bash намного приятнее и проще, вы можете взглянуть на мою Bash Infinity Framework, код ниже был разработан для этой цели.

Function.AssignParamLocally() {
    local commandWithArgs=( $1 )
    local command="${commandWithArgs[0]}"

    shift

    if [[ "$command" == "trap" || "$command" == "l="* || "$command" == "_type="* ]]
    then
        paramNo+=-1
        return 0
    fi

    if [[ "$command" != "local" ]]
    then
        assignNormalCodeStarted=true
    fi

    local varDeclaration="${commandWithArgs[1]}"
    if [[ $varDeclaration == '-n' ]]
    then
        varDeclaration="${commandWithArgs[2]}"
    fi
    local varName="${varDeclaration%%=*}"

    # var value is only important if making an object later on from it
    local varValue="${varDeclaration#*=}"

    if [[ ! -z $assignVarType ]]
    then
        local previousParamNo=$(expr $paramNo - 1)

        if [[ "$assignVarType" == "array" ]]
        then
            # passing array:
            execute="$assignVarName=( \"\${@:$previousParamNo:$assignArrLength}\" )"
            eval "$execute"
            paramNo+=$(expr $assignArrLength - 1)

            unset assignArrLength
        elif [[ "$assignVarType" == "params" ]]
        then
            execute="$assignVarName=( \"\${@:$previousParamNo}\" )"
            eval "$execute"
        elif [[ "$assignVarType" == "reference" ]]
        then
            execute="$assignVarName=\"\$$previousParamNo\""
            eval "$execute"
        elif [[ ! -z "${!previousParamNo}" ]]
        then
            execute="$assignVarName=\"\$$previousParamNo\""
            eval "$execute"
        fi
    fi

    assignVarType="$__capture_type"
    assignVarName="$varName"
    assignArrLength="$__capture_arrLength"
}

Function.CaptureParams() {
    __capture_type="$_type"
    __capture_arrLength="$l"
}

alias @trapAssign='Function.CaptureParams; trap "declare -i \"paramNo+=1\"; Function.AssignParamLocally \"\$BASH_COMMAND\" \"\$@\"; [[ \$assignNormalCodeStarted = true ]] && trap - DEBUG && unset assignVarType && unset assignVarName && unset assignNormalCodeStarted && unset paramNo" DEBUG; '
alias @param='@trapAssign local'
alias @reference='_type=reference @trapAssign local -n'
alias @var='_type=var @param'
alias @params='_type=params @param'
alias @array='_type=array @param'
2
27.01.2020, 19:46

Именованные аргументы просто не так, как был разработан синтаксис Bash. Bash был разработан как итеративное усовершенствование оболочки Bourne. Таким образом, он должен гарантировать, что определенные вещи работают между двумя оболочками в максимально возможной степени. Таким образом, не означает, что упрощает создание сценариев в целом, это просто должно быть лучше, чем Bourne, при этом гарантируя, что если вы возьмете сценарий из среды Bourne на bash , он как можно проще. Это нетривиально, поскольку многие оболочки все еще рассматривают Борна как стандарт де-факто. Поскольку люди пишут свои сценарии так, чтобы они были совместимы с Борном (для этой переносимости), необходимость остается в силе и вряд ли когда-нибудь изменится.

Вам, вероятно, лучше полностью взглянуть на другой сценарий оболочки (например, python или что-то в этом роде), если это вообще возможно. Если вы сталкиваетесь с языковыми ограничениями, вам нужно начать использовать новый язык.

1
27.01.2020, 19:46
assign () 
{ 
    if [ -z ${!1} ]; then
        eval $1=$2
    else
        if [[ ${!1} != *$2* ]]; then
            eval $1=${!1}:$2
        fi
    fi
}

$ echo =$x=
==
$ assign x y
$ echo =$x=
=y=
$ assign x y
$ echo =$x=
=y=
$ assign x z
$ echo =$x=
=y:z=

Подходит ли это?

1
27.01.2020, 19:46

Вы можете использовать eval для установки параметра. Описание этой команды можно найти здесь. Следующее использование eval является неправильным:

wrong(){
  eval $1=$2
}

Что касается дополнительной оценки evalделает, вы должны использовать

assign(){
  eval $1='$2'
}

Проверьте результаты использования этих функций:

$ X1='$X2'
$ X2='$X3'
$ X3='xxx'
$ 
$ echo :$X1:
:$X2:
$ echo :$X2:
:$X3:
$ echo :$X3:
:xxx:
$ 
$ wrong Y $X1
$ echo :$Y:
:$X3:
$ 
$ assign Y $X1
$ echo :$Y:
:$X2:
$ 
$ assign Y "hallo world"
$echo :$Y:
:hallo world:
$ # the following may be unexpected
$ assign Z $Y
$ echo ":$Z:"
:hallo:
$ # so you have to quote the second argument if its a variable
$ assign Z "$Y"
$ echo ":$Z:"
:hallo world:

Но вы можете достичь своей цели без использования eval. Я предпочитаю этот способ, который более прост.

Следующая функция делает подстановку правильным способом (я надеюсь)

augment(){
  local CURRENT=$1
  local AUGMENT=$2
  local NEW
  if [[ -z $CURRENT ]]; then
    NEW=$AUGMENT
  elif [[ ! ( ( $CURRENT = $AUGMENT ) || ( $CURRENT = $AUGMENT:* ) || \
    ( $CURRENT = *:$AUGMENT ) || ( $CURRENT = *:$AUGMENT:* ) ) ]]; then
    NEW=$CURRENT:$AUGMENT
  else
    NEW=$CURRENT
    fi
  echo "$NEW"
}

Проверьте следующий результат

augment /usr/bin /bin
/usr/bin:/bin

augment /usr/bin:/bin /bin
/usr/bin:/bin

augment /usr/bin:/bin:/usr/local/bin /bin
/usr/bin:/bin:/usr/local/bin

augment /bin:/usr/bin /bin
/bin:/usr/bin

augment /bin /bin
/bin


augment /usr/bin: /bin
/usr/bin::/bin

augment /usr/bin:/bin: /bin
/usr/bin:/bin:

augment /usr/bin:/bin:/usr/local/bin: /bin
/usr/bin:/bin:/usr/local/bin:

augment /bin:/usr/bin: /bin
/bin:/usr/bin:

augment /bin: /bin
/bin:


augment : /bin
::/bin


augment "/usr lib" "/usr bin"
/usr lib:/usr bin

augment "/usr lib:/usr bin" "/usr bin"
/usr lib:/usr bin

Теперь вы можете использовать функцию augment следующим образом, чтобы установить переменную:

PATH=`augment PATH /bin`
CLASSPATH=`augment CLASSPATH /bin`
LD_LIBRARY_PATH=`augment LD_LIBRARY_PATH /usr/lib`
2
27.01.2020, 19:46

О ИМЕННЫХ АРГУМЕНТАХ:

Это делается очень просто, и bash вообще не требуется - это базовое поведение присвоения через расширение параметра, определенное POSIX:

: ${PATH:=this is only assigned to \$PATH if \$PATH is null or unset}

Для демонстрации аналогично @Graeme, но в переносимом виде:

_fn() { echo "$1 ${2:-"$1"} $str" ; }

% str= ; _fn "${str:=hello}"
> hello hello hello

И там я делаю str= только для того, чтобы убедиться, что он имеет нулевое значение, потому что расширение параметра имеет встроенную защиту от переназначения окружения оболочки в строке, если оно уже установлено.

РЕШЕНИЕ:

Для вашей конкретной проблемы я не считаю, что именованные аргументы необходимы, хотя они, конечно, возможны. Используйте $IFS вместо этого:

assign() { oFS=$IFS ; IFS=: ; add=$* 
    set -- $PATH ; for p in $add ; do { 
        for d ; do [ -z "${d%"$p"}" ] && break 
        done ; } || set -- $* $p ; done
    PATH= ; echo "${PATH:="$*"}" ; IFS=$oFS
}

Вот что получается при запуске:

% PATH=/usr/bin:/usr/yes/bin
% assign \
    /usr/bin \
    /usr/yes/bin \
    /usr/nope/bin \
    /usr/bin \
    /nope/usr/bin \
    /usr/nope/bin

> /usr/bin:/usr/yes/bin:/usr/nope/bin:/nope/usr/bin

% echo "$PATH"
> /usr/bin:/usr/yes/bin:/usr/nope/bin:/nope/usr/bin

% dir="/some crazy/dir"
% p=`assign /usr/bin /usr/bin/new "$dir"`
% echo "$p" ; echo "$PATH"
> /usr/bin:/usr/yes/bin:/usr/nope/bin:/nope/usr/bin:/some crazy/dir:/usr/bin/new
> /usr/bin:/usr/yes/bin:/usr/nope/bin:/nope/usr/bin:/some crazy/dir:/usr/bin/new

Заметили, что он добавил только те аргументы, которых еще не было в $PATH или которые были раньше? Или даже то, что он вообще принял более одного аргумента? $IFS - это удобно.

0
27.01.2020, 19:46

Со стандартным синтаксисом sh (будет работать в bash , а не только в bash ]), вы можете сделать:

assign() {
  eval '
    case :${'"$1"'}: in
      (::) '"$1"'=$2;;   # was empty, copy
      (*:"$2":*) ;;      # already there, do nothing
      (*) '"$1"'=$1:$2;; # otherwise, append with a :
    esac'
}

Как и для решений, использующих bash declare , это безопасно , если $ 1 содержит допустимое имя переменной.

1
27.01.2020, 19:46

Я не могу найти ничего похожего на ruby, python и т. д., но мне кажется, что это ближе

foo() {
  BAR="$1"; BAZ="$2"; QUUX="$3"; CORGE="$4"
 ...
}

На мой взгляд, читабельность лучше, 4 строки избыточны для объявления имен ваших параметров. Выглядит ближе к современным языкам.

-2
27.01.2020, 19:46

Теги

Похожие вопросы