Итерировать строки строковой переменной в bash

Сейчас, когда поддержка JFX для ARM со стороны Oracle прекращена, я бы попробовал https://wiki.openjdk.java.net/display/OpenJFX/Building+OpenJFX

5
16.05.2019, 04:15
2 ответа

Это хорошая ситуация для использования readarray/mapfile:

readarray -t usbs < <(lsblk -o NAME,TRAN,VENDOR,MODEL | grep usb)

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

В вашем случае получится такой массив, как:

usbs=(
'sdb   usb    Kingston DataTraveler 2.0'
'sdc   usb    Kingston DT 101 G2'
)

Как и вы, вы присваиваете весь вывод одной переменной (, а не массиву ), что по существу делает это:

usbs='sdb   usb    Kingston DataTraveler 2.0
sdc   usb    Kingston DT 101 G2 '

Чтобы сделать это массивом, вы должны:

usbs=($(lsblk -o NAME,TRAN,VENDOR,MODEL | grep usb))

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

usbs=(
sdb
usb
Kingston
DataTraveler
2.0
sdc
usb
Kingston
DT
101
G2
)

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

First, I'd say it's not the right way to address the problem. It's a bit like saying "You should not murder people because otherwise you'll go to jail."

Similarly, you don't quote your variable because otherwise you're introducing security vulnerabilities. You quote your variables because it is wrong not to (but if the fear of the jail can help, why not).

  • Stéphane Chazelas

В случае for i in ${usbs[@]}; doiбудет установлено на каждое слово (, разделенное пробелом )в usbs. Если вы процитируете его как for i in "${usbs[@]}"; do,тогда iбудет установлен для каждого элемента из usbs, как требуется.

10
27.01.2020, 20:32

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

 usbs=$( lsusb... )
 IFS=$'\n'  # ksh bash zsh; in other shells you may need to quote an actual newline
 set -o noglob  # or more tersely set -f
 for i in $usbs; do
   printf '%s\n' "$i" # not echo which sometimes modifies some data
 done
 # if you do further things in the same script (or function) you may 
 # need to re-set IFS and/or glob, which may require saving them first

Для массива readarray/mapfile, предложенный Джесси _b, является самым простым, поскольку он уже разбивается на строки. Но вы можете сделать это "вручную" так же, как описано выше :

.
set -o noglob  # ditto 
IFS=$'\n' usbs=( $( lsusb... ) )  # only ksh up has arrays so $'' safe
# set +o noglob or set +f if needed
for i in "${usbs[@]}"; do # quoted array[@] forces splits equal to array elements only
  printf '%s\n' "$i"
done
4
27.01.2020, 20:32

Теги

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