Как отсортировать обратный массив в Bash - PullRequest
0 голосов
/ 22 сентября 2019

Как я могу изменить порядок, в котором я выполняю цикл for?Я хотел бы остановить модули в обратном порядке

#!/bin/bash
set -e
declare -a modules
mapfile -t modules < /app/appscripts/jenkins_modules
#jenkins_modules is txt file which consist string 01_docker 02_gtw 99_mq_gtw

for module in ${modules[@]} 
do
baseDir=/app/${module} # here is my script stopping modules
if [ -d ${baseDir} ]
then
    pushd ${baseDir}
    echo "Stopping module: ${module}\n"
    #./stop.sh ${baseDir}
    echo "Module: ${module} stopped\n"
    popd
  fi
done

Я попытался перевернуть сортировку в цикле, но это не работает.

#!/bin/bash
set -e
declare -a modules
mapfile -t modules < /app/appscripts/jenkins_modules
#jenkins_modules is txt file which consist string 01_docker 02_gtw 99_mq_gtw

for (( module=${#modules[@]}-1 ; module>=0 ; module-- ));
do
baseDir=/app/${module} # here script stopping modules
if [ -d ${baseDir} ]
then
    pushd ${baseDir}
    echo "Stopping module: ${module}\n"
    #./stop.sh ${baseDir}
    echo "Module: ${module} stopped\n"
    popd
  fi
done

Я также пытаюсь сортировать -р-н.Модули отображаются, но не сортируются в обратном порядке

#!/bin/bash
set -e
declare -a modules
mapfile -t modules < /app/appscripts/jenkins_modules
#jenkins_modules is txt file which consist string 01_docker 02_gtw 99_mq_gtw

for module in ${modules[@]| sort -rn}
do
baseDir=/app/${module} # here is my script stopping modules
if [ -d ${baseDir} ]
then
    pushd ${baseDir}
    echo "Stopping module: ${module}\n"
    #./stop.sh ${baseDir}
    echo "Module: ${module} stopped\n"
    popd
  fi
done

Ответы [ 4 ]

2 голосов
/ 24 сентября 2019

Все ваши попытки сдерживаются тем фактом, что /app/appscripts/jenkins_modules, кажется, содержит все элементы в одной строке, разделенные пробелом.Разделителем по умолчанию для mapfile является "\ n", поэтому ваш массив будет содержать только один элемент:

$ mapfile -d" " -t mod < <(echo "01_docker 02_gtw 99_mq_gtw");

$ echo ${#mod[@]}
3

$ mapfile -t mod < <(echo "01_docker 02_gtw 99_mq_gtw");

$ echo ${#mod[@]}
1

Как вы можете видеть, без указания разделителя, массив имеет один элемент.

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

$ mapfile -d" " -t mod < <(echo -n "01_docker 02_gtw 99_mq_gtw");

$ for ((i = ${#mod[@]}-1; i >= 0 ; i--)); do echo "$i - ${mod[$i]}"; done
2 - 99_mq_gtw
1 - 02_gtw
0 - 01_docker

$ mapfile -t mod < <(echo "01_docker 02_gtw 99_mq_gtw");

$ for ((i = ${#mod[@]}-1; i >= 0 ; i--)); do echo "$i - ${mod[$i]}"; done
0 - 01_docker 02_gtw 99_mq_gtw

(как вы можете видеть без разделителя, установленного для mapfile, он не будет работать)

Кроме того, будьте осторожны с новой строкой в ​​конце /app/appscripts/jenkins_modules, -t из mapfile не удалит ее, когда разделитель установлен в ''

. Лучше всего будет изменить/app/appscripts/jenkins_modules иметь по одному модулю на строку.

1 голос
/ 22 сентября 2019

использовать tac (объединять и печатать файлы в обратном порядке)

mapfile -t modules < <(tac /app/appscripts/jenkins_modules)

Кажется, у вас есть элементы в одной строке, разделенные пробелом, tac по умолчанию ожидает строки.Вы можете использовать это для преобразования пробелов в новые строки:

mapfile -t modules < <(</app/appscripts/jenkins_modules tr -s "[[:space:]]" "\n" | tac)
0 голосов
/ 23 сентября 2019

Я бы сделал это:

declare -a modules
mapfile -t modules < /app/appscripts/jenkins_modules
for (( i = 1; i <= "${#modules[@]}"; ++i )); do       # if you have 25 modules, is 1 .. 25
  (( j = -i ))                                        # j is -1 .. -25
  printf "%s\n" "${modules[$j]}"
done
$ declare -a modules=()
$ modules=( foo{1..5} )
$ printf "%s\n" "${modules[@]}"            # TIP: printf automatically loops if given too many arguments
foo1
foo2
foo3
foo4
foo5
$ printf "%s\n" "${modules[@]}" | tail -r  # TIP `tail -r` reverses the lines of its input
foo5
foo4
foo3
foo2
foo1
$ for (( i = 1; i <= "${#modules[@]}"; ++i )); do  # i takes on values 1 thru 5
> (( j = -i ))                                     # j takes on values -1 (last) to -5 (5th from last)
> printf "%s\n" "${modules[$j]}"
> done
foo5
foo4
foo3
foo2
foo1
0 голосов
/ 22 сентября 2019

В вашем цикле в стиле C, module не является элементом массива;это просто индекс:

for (( i=${#modules[@]}-1 ; i>=0 ; i-- ));
do
  module=${modules[i]}
  baseDir=/app/${module} # here script stopping modules
  if [ -d ${baseDir} ]
  then
    pushd ${baseDir}
    echo "Stopping module: ${module}\n"
    #./stop.sh ${baseDir}
    echo "Module: ${module} stopped\n"
    popd
  fi
done

Однако, может быть, стоит сначала просто построить массив в обратном порядке, а не использовать mapfile:

modules=()
while IFS= read -r module; do
  modules=("$module" "${modules[@]}")
done < /app/appscripts/jenkins_modules

...

for module in "${modules[@]}"; do
  baseDir=/app/$module
  [[ -d "$baseDir" ]] || continue
  pushd "$baseDir"
  ...
  popd
done
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...