Сохранить вывод команды в массив

Поскольку у вас уже есть список в $@, в качестве альтернативы можно было бы перебрать его и заснуть на 50 -метках пакета:

#!/bin/bash
channel=$1
shift

index=0
while [ "$#" -gt 0 ]
do
  (( ++index ))
  curl #... --data... "user":"'"$1"'"
  (( index % 50 == 0 )) && sleep 60
  shift
done

Я опустил большую часть команды curl, чтобы было легче увидеть структуру того, что я предлагаю. Первое изменение заключается в переносе имени канала в отдельную переменную и удалении этого аргумента. Затем оставшиеся элементы $@являются именами пользователей.

Следующая часть представляет собой простой цикл while, который выполняется до тех пор, пока в $@остаются элементы. Каждый раз в цикле мы:

  • увеличить счетчик
  • вызов curlпо телефону$1
  • sleepесли мы должны
  • shiftот первого элемента$@
2
03.07.2020, 12:07
3 ответа

Ваша команда сохраняет каждую разделенную пробелом -строку команды ssh в массиве. Итак, поскольку вы используете ssh, а затем запускаете id, whoamiи ps aux, , весь их вывод добавляется в массив, разделяя на пробелы (значение по умолчанию для $IFSпеременная ). Вы можете увидеть это с помощьюdeclare -p ar:

$ ar=($( ssh localhost sh -c "id;whoami;ps aux")) 
$ declare -p ar | head -c500
declare -a ar=([0]="uid=1000(terdon)" [1]="gid=1000(terdon)" [2]="groups=1000(terdon),3(sys),7(lp),10(wheel),14(uucp),56(bumblebee),84(avahi),96(scanner),209(cups),995(plugdev)" [3]="terdon" [4]="USER" [5]="PID" [6]="%CPU" [7]="%MEM" [8]="VSZ" [9]="RSS" [10]="TTY" [11]="STAT" [12]="START" [13]="TIME" [14]="COMMAND" [15]="root" [16]="1" [17]="0.0" [18]="0.0" [19]="174456" [20]="11996" [21]="a" [22]="b" [23]="f" [24]="R" [25]="Ss" [26]="Jun23" [27]="7:06" [28]="/sbin/init" [29]="root" [30]="2" 

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

Если вы хотите иметь массив только из трех элементов, по одному на команду, вам нужно использовать другой символ для разделения. Один из способов сделать это — отредактировать ваши команды так, чтобы они печатали уникальный символ после выполнения, а затем использовать mapfileдля чтения массива, сообщая ему о разделении на этот уникальный символ. Например,\0:

$ mapfile -d '' < <( ssh localhost sh -c "id; printf '\0'; whoami; printf '\0'; ps aux") ar

$ for i in 0 1 2; do echo "$i: ${ar[i]}"; done | head
0: uid=1000(terdon) gid=1000(terdon) groups=1000(terdon),3(sys),7(lp),10(wheel),14(uucp),56(bumblebee),84(avahi),96(scanner),209(cups),995(plugdev)

1: terdon

2: USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root           1  0.0  0.0 174456 11996 ?        Ss   Jun23   7:07 /sbin/init
root           2  0.0  0.0      0     0 ?        S    Jun23   0:00 [kthreadd]
root           3  0.0  0.0      0     0 ?        I<   Jun23   0:00 [rcu_gp]
root           4  0.0  0.0      0     0 ?        I<   Jun23   0:00 [rcu_par_gp]
root           6  0.0  0.0      0     0 ?        I<   Jun23   0:00 [kworker/0:0H-kblockd]
2
18.03.2021, 23:22

Попробуйте (bash4.4+)

readarray -td '' a < <(
  ssh -i id_rsa -T -y root@1.1.1.1 '
    id;     printf "\0"
    whoami; printf "\0"
    ps aux; printf "\0"'
)
id_output=${a[0]}
whoami_output=${a[1]}
ps_output=${a[2]}

sshуже вызывает оболочку (оболочку входа в систему этого rootпользователя там )для интерпретации командной строки. Для этого он объединяет аргументы. Таким образом, в вашем подходе запускается оболочка с -cи sh -c id;whoami;ps auxв качестве аргументов, и эта оболочка затем запускает sh -c id, whoamiи ps aux. sh -cздесь лишнее и может только вызвать путаницу.

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

Если вы хотите их распечатать, используйте:

printf %s "$id_output"

Чтобы удалить символ новой строки, вы можете:

id_output=${id_output%$'\n'}
4
18.03.2021, 23:22

Затратной частью sshявляется процесс аутентификации. Я бы использовал опцию ControlMaster, чтобы позволить нескольким отдельным сеансам sshсовместно использовать одно аутентифицированное соединение.

ssh_get () {
  ssh -o ControlMaster=auto -o ControlPersist=5 -i id_rsa -T -y root@1.1.1.1 "$@"
}

for cmd in id whoami "ps aux"; do
  ar+=("$(ssh_get "$cmd")")
done

Первый вызов будет выполнять аутентификацию, но после его выхода соединение sshостанется в фоновом режиме до 5 секунд (в соответствии с параметром ControlPersist), что позволит следующему вызову использовать это без повторной аутентификации. Накладные расходы на запуск самого sshминимальны.

1
18.03.2021, 23:22

Теги

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