IFS(내부 필드 구분 기호)를 여러 개의 연속 구분 기호에 대한 단일 구분 기호로 사용할 수 있습니까?

IFS(내부 필드 구분 기호)를 여러 개의 연속 구분 기호에 대한 단일 구분 기호로 사용할 수 있습니까?

공백이 아닌 값으로 IFS를 사용하여 배열을 구문 분석하면 빈 요소가 생성됩니다. 여러 구분 기호를 단일 구분 기호로 축소하는
것만으로는 충분하지 않습니다. 예를 들어 문제를 더 명확하게 설명할 수 있습니다. IFS를 조정하여 "정상적인" 결과를 얻을 수 있는 방법이 있습니까(IFS의 동작을 변경하는 관련 설정이 있습니까? .... 즉, 기본 공백 IFS와 동일한 동작입니다.tr -s

var=" abc  def   ghi    "
echo "============== IFS=<default>"
arr=($var)
for x in ${!arr[*]} ; do
   echo "# arr[$x] \"${arr[x]}\""
done
#
sfi="$IFS" ; IFS=':'
set -f # Disable file name generation (globbing)
       # (This  data won't "glob", but unless globbing     
       #  is actually needed, turn if off, because   
       #  unusual/unexpected combinations of data can glob!
       #  and they can do it in the most obscure ways...  
       #  With IFS, "you're not in Kansas any more! :)  
var=":abc::def:::ghi::::"
echo "============== IFS=$IFS"
arr=($var)
for x in ${!arr[*]} ; do
   echo "# arr[$x] \"${arr[x]}\""
done
echo "============== IFS=$IFS and tr"
arr=($(echo -n "$var"|tr -s "$IFS"))
for x in ${!arr[*]} ; do
   echo "# arr[$x] \"${arr[x]}\""
done
set +f     # enable globbing 
IFS="$sfi" # re-instate original IFS val
echo "============== IFS=<default>"

이것이 출력이다


============== IFS=<default>
# arr[0] "abc"
# arr[1] "def"
# arr[2] "ghi"
============== IFS=:
# arr[0] ""
# arr[1] "abc"
# arr[2] ""
# arr[3] "def"
# arr[4] ""
# arr[5] ""
# arr[6] "ghi"
# arr[7] ""
# arr[8] ""
# arr[9] ""
============== IFS=: and tr
# arr[0] ""
# arr[1] "abc"
# arr[2] "def"
# arr[3] "ghi"
============== IFS=<default>

답변1

bash맨페이지 에서 :

IFS 공백이 아닌 IFS의 모든 문자와 인접한 IFS 공백 문자가 함께 필드를 구분합니다. 공백 문자의 IFS 시퀀스도 구분 기호로 간주됩니다.

나타냅니다IFS 공백(공백, 탭 및 줄 바꿈)은 다른 구분 기호와 다르게 처리됩니다. 대체 구분 기호를 사용하여 완전히 동일한 동작을 얻으려면 tr또는 다음을 사용하여 구분 기호를 바꿀 수 있습니다 sed.

var=":abc::def:::ghi::::"
arr=($(echo -n $var | sed 's/ /%#%#%#%#%/g;s/:/ /g'))
for x in ${!arr[*]} ; do
   el=$(echo -n $arr | sed 's/%#%#%#%#%/ /g')
   echo "# arr[$x] \"$el\""
done

이것은 %#%#%#%#%"고유"(또는 매우 관련성이 없어야 함) 필드 내의 가능한 공백을 대체하는 마법의 값입니다. 필드에 공백이 없을 것이라고 확신하는 경우 이 부분을 제거하면 됩니다.

답변2

여러 개의(공백이 아닌) 연속 구분 기호를 제거하려면 두 개의(문자열/배열) 매개 변수 확장을 사용할 수 있습니다. 비결은 IFS배열 매개변수 확장을 위해 변수를 빈 문자열로 설정하는 것입니다.

이 내용은 다음과 같이 기록됩니다.man bash아래에분사:

값이 없는 매개변수 확장으로 인해 암시적으로 인용되지 않은 null 매개변수는 제거됩니다.

(
set -f
str=':abc::def:::ghi::::'
IFS=':'
arr=(${str})
IFS=""
arr=(${arr[@]})

echo ${!arr[*]}

for ((i=0; i < ${#arr[@]}; i++)); do 
   echo "${i}: '${arr[${i}]}'"
done
)

답변3

gawk를 사용하여 이 작업을 수행할 수도 있지만 보기에는 좋지 않습니다.

var=":abc::def:::ghi::::"
out=$( gawk -F ':+' '
  {
    # strip delimiters from the ends of the line
    sub("^"FS,"")
    sub(FS"$","")
    # then output in a bash-friendly format
    for (i=1;i<=NF;i++) printf("\"%s\" ", $i)
    print ""
  }
' <<< "$var" )
eval arr=($out)
for x in ${!arr[*]} ; do
  echo "# arr[$x] \"${arr[x]}\""
done

산출

# arr[0] "abc"
# arr[1] "def"
# arr[2] "ghi"

답변4

bash IFS는 연속 구분 기호 문자를 단일 구분 기호(공백이 아닌 구분 기호의 경우)로 처리하는 내부 방법을 제공하지 않기 때문에 전체 bash 버전을 구성했습니다(tr, awk, sed와 같은 외부 호출을 사용하는 것과 비교).

다중 문자 IFS를 처리할 수 있습니다.

다음은 이 Q/A 페이지에 표시된 tr및 옵션에 대한 유사한 테스트와 함께 이에 대한 실행 시간 결과입니다 awk. 테스트는 단지 어레이 구축(I/O 없음)의 10000회 반복을 기반으로 합니다.

pure bash     3.174s (28 char IFS)
call (awk) 0m32.210s  (1 char IFS) 
call (tr)  0m32.178s  (1 char IFS) 

이것이 출력이다

# dlm_str  = :.~!@#$%^&()_+-=`}{][ ";></,
# original = :abc:.. def:.~!@#$%^&()_+-=`}{][ ";></,'single*quote?'..123:
# unified  = :abc::::def::::::::::::::::::::::::::::'single*quote?'::123:
# max-w 2^ = ::::::::::::::::
# shrunk.. = :abc:def:'single*quote?':123:
# arr[0] "abc"
# arr[1] "def"
# arr[2] "'single*quote?'"
# arr[3] "123"

이게 스크립트야

#!/bin/bash

# Note: This script modifies the source string. 
#       so work with a copy, if you need the original. 
# also: Use the name varG (Global) it's required by 'shrink_repeat_chars'
#
# NOTE: * asterisk      in IFS causes a regex(?) issue,     but  *  is ok in data. 
# NOTE: ? Question-mark in IFS causes a regex(?) issue,     but  ?  is ok in data. 
# NOTE: 0..9 digits     in IFS causes empty/wacky elements, but they're ok in data.
# NOTE: ' single quote  in IFS; don't know yet,             but  '  is ok in data.
# 
function shrink_repeat_chars () # A 'tr -s' analog
{
  # Shrink repeating occurrences of char
  #
  # $1: A string of delimiters which when consecutively repeated and are       
  #     considered as a shrinkable group. A example is: "   " whitespace delimiter.
  #
  # $varG  A global var which contains the string to be "shrunk".
  #
# echo "# dlm_str  = $1" 
# echo "# original = $varG" 
  dlms="$1"        # arg delimiter string
  dlm1=${dlms:0:1} # 1st delimiter char  
  dlmw=$dlm1       # work delimiter  
  # More than one delimiter char
  # ============================
  # When a delimiter contains more than one char.. ie (different byte` values),    
  # make all delimiter-chars in string $varG the same as the 1st delimiter char.
  ix=1;xx=${#dlms}; 
  while ((ix<xx)) ; do # Where more than one delim char, make all the same in varG  
    varG="${varG//${dlms:$ix:1}/$dlm1}"
    ix=$((ix+1))
  done
# echo "# unified  = $varG" 
  #
  # Binary shrink
  # =============
  # Find the longest required "power of 2' group needed for a binary shrink
  while [[ "$varG" =~ .*$dlmw$dlmw.* ]] ; do dlmw=$dlmw$dlmw; done # double its length
# echo "# max-w 2^ = $dlmw"
  #
  # Shrik groups of delims to a single char
  while [[ ! "$dlmw" == "$dlm1" ]] ; do
    varG=${varG//${dlmw}$dlm1/$dlm1}
    dlmw=${dlmw:$((${#dlmw}/2))}
  done
  varG=${varG//${dlmw}$dlm1/$dlm1}
# echo "# shrunk.. = $varG"
}

# Main
  varG=':abc:.. def:.~!@#$%^&()_+-=`}{][ ";></,'\''single*quote?'\''..123:' 
  sfi="$IFS"; IFS=':.~!@#$%^&()_+-=`}{][ ";></,' # save original IFS and set new multi-char IFS
  set -f                                         # disable globbing
  shrink_repeat_chars "$IFS" # The source string name must be $varG
  arr=(${varG:1})    # Strip leading dlim;  A single trailing dlim is ok (strangely
  for ix in ${!arr[*]} ; do  # Dump the array
     echo "# arr[$ix] \"${arr[ix]}\""
  done
  set +f     # re-enable globbing   
  IFS="$sfi" # re-instate the original IFS
  #
exit

관련 정보