다음은 출력을 my_command
행 배열로 그룹화한다고 생각합니다.
IFS='\n' array_of_lines=$(my_command);
따라서 이는 $array_of_lines[1]
출력의 첫 번째 줄 my_command
, $array_of_lines[2]
두 번째 줄 등을 참조합니다.
그러나 위의 명령은 잘 작동하지 않는 것 같습니다. 내가 확인한 대로 my_command
출력을 문자별로 분할하는 것 같습니다. 이는 배열의 요소를 한 줄씩 인쇄하는 것으로 생각됩니다. 나는 또한 이것을 확인했습니다 :n
print -l $array_of_lines
echo $array_of_lines[1]
echo $array_of_lines[2]
...
두 번째 시도에서 다음을 eval
추가하면 도움이 될 것이라고 생각했습니다.
IFS='\n' array_of_lines=$(eval my_command);
그러나 나는 그것이 없는 것과 똑같은 결과를 얻습니다.
마지막으로 답변을 따르세요.zsh에서 공백이 있는 요소 나열IFS
, 또한 zsh에게 입력을 분할하고 요소를 배열로 수집하는 방법을 알려주는 대신 매개변수 확장 플래그를 사용해 보았습니다 . 즉:
array_of_lines=("${(@f)$(my_command)}");
하지만 여전히 동일한 결과를 얻습니다(분할은 에서 발생함 n
).
이와 관련하여 다음과 같은 질문이 있습니다.
Q1.무엇인가요"옳은"여러 줄의 명령 출력을 수집하는 방법은 무엇입니까?
Q2.IFS
개행만으로 분할을 지정하는 방법은 무엇입니까 ?
Q3.위의 세 번째 시도에서처럼 매개변수 확장 플래그(즉, 사용)를 사용하여 분할을 지정하면 @f
zsh가 값을 무시합니까 IFS
? 위의 방법이 왜 작동하지 않습니까?
답변1
TL, 박사:
array_of_lines=("${(@f)$(my_command)}")
첫 번째 오류(→ Q2): 두 문자로 IFS='\n'
설정 하고 . 줄 바꿈을 설정하려면 를 사용하십시오 .IFS
\
n
IFS
IFS=$'\n'
두 번째 오류: 변수를 배열 값으로 설정하려면 요소 주위에 괄호가 필요합니다 array_of_lines=(foo bar)
.
연속된 공백이 단일 구분 기호로 처리되기 때문에 빈 줄을 제거한다는 점을 제외하면 작동합니다.
IFS=$'\n' array_of_lines=($(my_command))
다음에서 공백 문자를 두 배로 늘려 마지막 줄을 제외하고 빈 줄을 유지할 수 있습니다 IFS
.
IFS=$'\n\n' array_of_lines=($(my_command))
후행 빈 줄을 유지하려면 명령 출력에 무언가를 추가해야 합니다. 이는 구문 분석이 아닌 명령 대체 자체에서 발생하기 때문입니다.
IFS=$'\n\n' array_of_lines=($(my_command; echo .)); unset 'array_of_lines[-1]'
(출력이 my_command
구분되지 않은 줄로 끝나지 않는다고 가정하고 종료 상태도 잃게 됩니다 my_command
.)
위의 모든 코드 조각은 IFS
기본값이 아닌 값을 유지하므로 후속 코드를 엉망으로 만들 수 있습니다. 로컬 설정을 유지하려면 IFS
전체를 IFS
로컬을 선언하는 함수에 넣으세요(여기서 명령의 종료 상태도 유지된다는 점에 유의하세요).
collect_lines() {
local IFS=$'\n\n' ret
array_of_lines=($("$@"; ret=$?; echo .; exit $ret))
ret=$?
unset 'array_of_lines[-1]'
return $ret
}
collect_lines my_command
그러나 나는 그것을 함부로 다루지 않는 것을 권장합니다 IFS
. 대신 f
에 확장 플래그를 사용하여 개행 문자로 분할합니다(→ Q1).
array_of_lines=("${(@f)$(my_command)}")
또는 뒤에 빈 줄을 유지하십시오.
array_of_lines=("${(@f)$(my_command; echo .)}")
unset 'array_of_lines[-1]'
거기에서는 의 가치가 IFS
중요하지 않습니다. 테스트에서 분할 IFS
인쇄 명령을 사용한 것 같습니다(→ Q3).$array_of_lines
답변2
두 가지 문제: 첫째, 분명히 큰따옴표는 백슬래시 이스케이프를 설명하지 않습니다(죄송합니다 :). $'...'
따옴표를 사용하세요 . 에 따르면 man zshparam
단어를 배열로 수집하려면 해당 단어를 괄호로 묶어야 합니다. 그래서 이것은 작동합니다 :
% touch 'a b' c d 'e f'
% IFS=$'\n' arr=($(ls)); print -l $arr
a b
c
d
e f
% print $arr[1]
a b
귀하의 질문에 답변을 드릴 수 없습니다 3. 그렇게 심오한 것을 알 필요가 없기를 바랍니다 :).
답변3
tr을 사용하여 개행 문자를 공백으로 바꿀 수도 있습니다.
lines=($(mycommand | tr '\n' ' '))
select line in ("${lines[@]}"); do
echo "$line"
break
done