Bash

在bash中迭代字元串變數的行

  • May 18, 2019

我有一個腳本,我想在其中使用命令列出 USB 設備lsblk

命令:

$ lsblk -o NAME,TRAN,VENDOR,MODEL | grep usb

這導致

sdb   usb    Kingston DataTraveler 2.0
sdc   usb    Kingston DT 101 G2 

我想將結果保存在一個變數中以便以後工作,所以我寫

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

我所期望的是變數usbs將結果儲存在上面的兩行中。但是如果我執行:

for i in ${usbs[@]}; do
 echo $i
done

我把結果分成幾個詞:

sdb
usb
Kingston
DataTraveler
2.0
sdc
usb
Kingston
DT
101
G2

問題: 有沒有一種方法可以使用該grep命令將命令的結果儲存為整行兩行?

我更願意知道是否有一個簡單的解決方案,而不是將結果轉儲到文件中然後讀取它。

這是使用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
)

正如幾位評論者所指出的,並且通常始終是最佳實踐,應引用變數。在這種情況下,您必須並且通常應該始終引用您的變數。

首先,我想說這不是解決問題的正確方法。這有點像說“你不應該殺人,否則你會進監獄”。

同樣,您不要引用您的變數,因為否則您將引入安全漏洞。您引用變數是因為不這樣做是錯誤的(但如果對監獄的恐懼可以提供幫助,為什麼不這樣做)。

  • 斯蒂芬·查澤拉斯

在 的情況下for i in ${usbs[@]}; doi將設置為 中的每個單詞(由空格分隔)usbs。如果您像 一樣引用它for i in "${usbs[@]}"; do,那麼i將根據需要設置為 的每個元素usbs

這主要是新行和 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

Jesse_b 建議的數組readarray/mapfile是最簡單的,因為它已經在行處分割。但是您可以像上面那樣“手動”完成它:

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

引用自:https://unix.stackexchange.com/questions/519140