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
이 명령을 사용하여 명령 결과를 두 개의 전체 라인으로 저장하는 방법이 있습니까 ?
결과를 파일에 덤프한 다음 읽는 것보다 간단한 해결책이 있는지 알고 싶습니다.
답변1
이것은 좋은 사용 사례입니다배열/맵 파일 읽기:
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[@]}; do
각각 i
으로 설정됩니다.단어(공백으로 구분) in usbs
. 이렇게 인용하면 각각으로 설정됩니다 for i in "${usbs[@]}"; do
.i
요소usbs
, 예상대로 .
답변2
이건 대부분 사기에요새 줄과 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
Jesse_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
답변3
grep
질문: 명령을 사용하여 명령 결과를 두 개의 전체 라인으로 저장하는 방법이 있습니까 ?
예, 할당 코드가 정확합니다.
usbs=$(lsblk -o NAME,TRAN,VENDOR,MODEL | grep usb)
이는 정확히 필요한 작업을 수행합니다. 단일 변수(배열이 아님)에 lsblk
개행 문자로 구분된 두 줄을 저장합니다. 그러나 for
루프는 이 변수를 읽는 데 적합한 도구가 아닙니다. 루프가 while
훨씬 더 좋습니다. 일부 독자에는 USB 장치가 연결되어 있지 않을 수 있으므로 가상 데이터의 예는 다음과 같습니다.
t=$(echo foo bar; echo baz bing;)
while read i ; do echo "$i" ; done <<< "$t"
산출:
foo bar
baz bing
더 짧은 방법은 다음과 같습니다.
xargs -L 1 <<< "$t"
참고: 평범하지만POSIX스타일 변수 x
는 배열이 아니므로 배열 표기법을 사용하여 식별 bash
할 수 있으며 배열이 아니라고 불평하지 않습니다. 데모:x
x
x=f
echo $x ${x[0]} ${x[@]}
산출:
f f f
그러나 x
배열은 아닙니다. 그렇다면 이 코드(사용bash
매개변수 변환 A
옮기다연산자), 확실히 배열을 출력합니다:
echo "${x[@]@A}"
...그렇지 않습니다:
x='f'
비교를 위해 위의 모습과 어떻게 보이는지 비교해 보겠습니다.예정렬. 먼저 매우 유사한 배열을 만든 y
다음 사용하십시오.A
옮기다차이점을 표시하는 연산자:
y=(f)
echo "${y[@]@A}"
산출:
declare -a y=([0]="f")