zsh를 사용하여 일치하지 않는 줄을 삭제하지 않고 지우십시오.

zsh를 사용하여 일치하지 않는 줄을 삭제하지 않고 지우십시오.

배열에서 일치하지 않는 행을 삭제하려면 다음과 같이 하면 됩니다.

array=( ${(M)array:#*${filter}*} )

그러나 배열도 압축합니다. 하지만 나중에 원래 길이의 다른 배열과 병합할 것이므로 배열을 동일한 길이로 유지해야 합니다. 즉, 일치하지 않는 행을 실제로 삭제하지 않고 "비우고" 싶습니다. 배열의 길이를 변경하거나 일치하는 행의 인덱스 번호를 변경하고 싶지 않습니다.

현재 일치하지 않는 문자열을 자리 표시자로서 더미 문자열로 바꾸고, 병합한 다음, 더미 문자열을 제거하여 이 문제를 해결하고 있지만 이는 서투른 작업입니다.

답변1

따옴표 없이 확장하면 빈 요소가 제거됩니다. Korn과 같은 셸에서처럼 큰따옴표와 플래그가 필요 @하거나 이를 사용 하여 보존합니다.[@]

${var/pattern/replacement}또한 Korn 스타일을 대신 사용해야 합니다 ${array:#pattern}.제거하다요소, 아니편집하다그들의 콘텐츠. 그래서:

set -o extendedglob
array=( "${array[@]/#%^*$filter*}" )
print -rC1 -- "$array[@]"

여기서는 일치 항목을 시작 부분에 고정하고 끝 부분에 고정합니다(ksh에서 결합할 수 없다는 점을 제외하면 Korn 셸과 동일) #. 연산자 에서 패턴을 전체적으로 일치시킵니다. 고정은 암시적입니다. , while 전체의 내용과 일치해야 하며 시작과 끝 부분에만 고정됩니다./%${param:#pattern}pattern$param${param#pattern}${param%pattern}

^extendedglob부정 연산자 입니다 .

이제 zsh확산 연산자는 특히 여러 연산자를 결합하기 시작할 때 매우 복잡해질 수 있지만 대부분의 다른 언어에서와 마찬가지로 항상 이를 수행하고 배열 요소를 반복할 수 있습니다.

요소를 제자리에서 편집하는 것과 같습니다.

for (( i = 1; i <= $#array; i++ ))
  if [[ $array[i] != *$filter* ]] array[i]=

또는 새 배열을 만듭니다.

new_array=()
for element ( "$array[@]" )
  case $element in
    (*$filter*) new_array+=( "$element" );;
    (*)         new_array+=( '' )
  esac

또는:

new_array=()
for element ( "$array[@]" ) {
  [[ $element = *$filter* ]] || element=
  new_array+=( "$element" )
}

답변2

array=( "${(@M)array##*${filter}*}" )

이는 배열의 모든 요소를 ​​유지하고 각 요소에서 가장 긴 접두사 제거를 수행하지만 일치하는 부분만 유지되도록 ##pattern플래그를 사용합니다 . 빈 요소가 결과에서 제거되지 않도록 M큰따옴표와 플래그가 필요합니다.@

관련 정보