Аргументы оболочки печати в обратном порядке

Я использовал csvtool однажды, и он сохранил меня много времени и проблемы. Вызываемый от оболочки.

http://caml.inria.fr/cgi-bin/hump.en.cgi?contrib=447

12
25.09.2011, 19:03
7 ответов

eval единственный портативный путь состоит в том, чтобы получить доступ к позиционному параметру своим динамично выбранным положением. Ваш сценарий был бы более четким, если бы Вы явно циклично выполнились на индексе, а не значениях (который Вы не используете). Обратите внимание, что Вам не нужно expr если Вы не хотите, чтобы Ваш сценарий работал в старинных Оболочках Bourne; $((…)) арифметика находится в POSIX. Ограничьте использование eval к самому маленькому фрагменту; например, не использовать eval echo, присвойте значение временной переменной.

i=$#
while [ "$i" -gt 0 ]; do
  if [ "$i" -ne 3 ] && [ "$i" -ne 2 ]; then
    eval "value=\${$i}"
    echo "Parameter $i is $value"
  fi
  i=$((i-1))
done

В ударе можно использовать ${!i} означать значение параметра, имя которого $i. Это работает когда $i или именованный параметр или число (обозначение позиционного параметра). В то время как Вы в нем, можно использовать другие удобные функции удара.

for ((i=$#; i>0; i--)); do
  if ((i != 3 && i != 4)); then
    echo "Parameter $i is ${!i}"
  fi
done
13
27.01.2020, 19:55
  • 1
    я не могу использовать arg поскольку им заказывают правильно и не наоборот. К использованию expr, Я ограничен для использования стандарта только. –  WarrenFaith 25.09.2011, 19:07
  • 2
    @WarrenFaith, Если Ваш сценарий запускается с #!/bin/bash, можно использовать ${!i} и (()). Если Вы хотите придерживаться стандарта sh, они не доступны, но $((…)) . –  Gilles 'SO- stop being evil' 25.09.2011, 19:10
  • 3
    Хорошо, я думаю, что могу работать с этим :) –  WarrenFaith 25.09.2011, 19:11
  • 4
    Обратите внимание, что старинные Оболочки Bourne не смогли бы получить доступ к позиционным параметрам вне 9$ так или иначе. –  Stéphane Chazelas 12.06.2015, 17:41
  • 5
    eval не единственный портативный путь, поскольку Ryan показал. –  Stéphane Chazelas 12.06.2015, 18:04

Это - корректное и неопасное использование оценки. Вы полностью управляете содержанием, которое Вы evalлуг.

Если это все еще дает Вам плохо чувства, то, если Вы не заботитесь о мобильности, можно использовать Bash ${!i} косвенный синтаксис.

2
27.01.2020, 19:55

Я сохраняю сценарий reverse на моем пути, который делает это:

#!/bin/sh

if [ "$#" -gt 0 ]; then
    arg=$1
    shift
    reverse "$@"
    printf '%s\n' "$arg"
fi

Использование в качестве примера:

$ reverse a b c '*' '-n'
-n
*
c
b
a

Можно также использовать функцию вместо специализированного сценария.

7
27.01.2020, 19:55
  • 1
    Обратите внимание, что тот один (вопреки другим ответам, отправленным до сих пор), также работал бы в Оболочке Bourne (не, что существует любая причина использовать ту оболочку в наше время) –  Stéphane Chazelas 12.06.2015, 17:43
  • 2
    @StéphaneChazelas: Почему кавычка $#?   это может быть что-нибудь кроме неотрицательного целого числа? –  G-Man Says 'Reinstate Monica' 12.06.2015, 20:05
  • 3
    @G-Man, оставляя переменную закрывшей кавычки в контексте списка вызывает split+glob оператор. Нет причины, почему Вы хотели бы вызвать ее здесь. Это не имеет никакого отношения к содержанию переменной. См. также unix.stackexchange.com/a/171347 к концу. Также обратите внимание, что некоторые оболочки (тире, шикарный, например) все еще, наследовали IFS от среды. –  Stéphane Chazelas 12.06.2015, 21:44
  • 4
    я нашел, что на Android должен был объявить local arg=$1 –  starfry 04.09.2016, 12:50
declare -a argv=( "$@" )
for (( i=$((${#argv[@]}-1)) ; i>=0 ; i=$(($i-1)) )) ; do
        echo "${argv[$i]}"
        # use "${argv[$i]}" in here...
done
-3
27.01.2020, 19:55

С zsh :

$ set a 'foo bar' c '' '*'
$ printf '<%s>\n' "${(Oa)@}"
<*>
<>
<c>
<foo bar>
<a>

Oa - это флаг раскрытия параметра для сортировки элементов массива при раскрытии в обратных индексах массива.

Чтобы исключить 3 и 4:

$ printf '<%s>\n' "${(Oa)@[5,-1]}" "${(Oa)@[1,2]}"
<*>
<foo bar>
<a>
1
27.01.2020, 19:55

Предполагая, что параметры позиционирования не содержат символов новой строки:

[ "$#" -gt 0 ] && printf '%s\n' "$@" | #print in order
sed '3,4 d' |                          #skip 3 and 4
tac                                    #reverse (try tail -r on
                                       #non-GNU systems).

Test:

set 1 2 3 4 5 6
printf '%s\n' "$@" | 
sed '3,4 d' |
tac

Test output:

6
5
2
1
2
27.01.2020, 19:55

Практически с любой оболочкой:

printf '{ PS4=\${$(($#-$x))}; } 2>&3; 2>&1\n%.0s' |
x=LINENO+1 sh -sx "$@" 3>/dev/null

И вам не требуется для использования подоболочки. Например:

set -x a b c
{ last= PS4=\${last:=\${$#}}; set +x; } 2>/dev/null
echo "$last"

... печатает ...

c

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

tofro() case $1 in (*[!0-9]*|'') ! :;;(*) set "$1"
        until   [ "$1" -eq "$(($#-1))" ]    &&
                shift && alias args=":; printf \
            \"%.\$((\$??\${#*}:0))s%.\$((!\$??\${#*}:0))s\n\" $* "
        do      [ "$#" -gt 1 ] &&
                set "$@ \"\${$#}\" " '"${'"$((1+$1-$#))"'}"' ||
                set "$1" '"$1" "${'"$1"'}"'
        done;   esac

Это не пытается сохранить буквальные значения для каких-либо аргументов, а помещает такую ​​строку в псевдоним args :

:;printf    "%.$(($??${#*}:0))s%.$((!$??${#*}:0))s\n" \
            "$1" "${3}" "${2}"  "${2}" "${3}"  "${1}"

... и поэтому сохраняет только ссылки на параметры в обратном порядке и вперед. Он будет хранить до счетчика, заданного в качестве аргумента.Таким образом, указанный выше псевдоним был сгенерирован следующим образом:

tofro 3

printf влияет на поведение на основе возвращаемого значения предыдущей команды, которое всегда является : нулевой командой. , и так обычно верно. printf будет пропускать половину своих аргументов при каждой печати, что по умолчанию приводит к распечатке аргументов от наименьшего до наибольшего. Однако, если вы просто выполните:

! args

... он напечатает их в обратном порядке.

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

set one two three
tofro 3
args; ! args
shift; args; ! args

... который печатает ...

one
two
three
three
two
one
two
three


three
two

Но сброс псевдонима может быть выполнен как:

tofro 2
args; ! args

... и поэтому он печатает ...

two
three
three
two
0
27.01.2020, 19:55

Теги

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