Programing

bash 쉘에서 하나의 문자열을 하나 이상의 공백으로 구분하여 여러 문자열로 나누는 방법은 무엇입니까?

lottogame 2020. 5. 8. 08:10
반응형

bash 쉘에서 하나의 문자열을 하나 이상의 공백으로 구분하여 여러 문자열로 나누는 방법은 무엇입니까?


각 두 단어 사이에 하나 이상의 공백이있는 많은 단어가 포함 된 문자열이 있습니다. 문자열을 개별 단어로 분리하여 반복 할 수 있습니까?

문자열은 인수로 전달됩니다. ${2} == "cat cat file". 어떻게 반복 할 수 있습니까?

또한 문자열에 공백이 있는지 어떻게 확인할 수 있습니까?


문자열 변수를 for루프에 전달하려고 했습니까 ? Bash는 공백으로 자동 분할됩니다.

sentence="This is   a sentence."
for word in $sentence
do
    echo $word
done

 

This
is
a
sentence.

개별 요소에 액세스 할 수 있도록 배열로 변환하는 것이 좋습니다.

sentence="this is a story"
stringarray=($sentence)

이제 개별 요소에 직접 액세스 할 수 있습니다 (0으로 시작).

echo ${stringarray[0]}

또는 반복하려면 문자열로 다시 변환하십시오.

for i in "${stringarray[@]}"
do
  :
  # do whatever on $i
done

물론 문자열을 통한 루핑은 이전에 답변되었지만 그 대답은 나중에 사용하기 위해 개별 요소를 추적하지 않는 단점이있었습니다.

for i in $sentence
do
  :
  # do whatever on $i
done

Bash Array Reference참조하십시오 .


쉘 "set"내장을 사용하십시오. 예를 들어

$ text 설정

그 후 $ text의 개별 단어는 $ 1, $ 2, $ 3 등이됩니다. 견고성을 위해 보통

세트-정크 $ 텍스트
시프트

$ text가 비어 있거나 대시로 시작하는 경우를 처리합니다. 예를 들면 다음과 같습니다.

text = "테스트입니다"
세트-정크 $ 텍스트
시프트
말을 위해; 하다
  에코 "[$ word]"
끝난

이것은 인쇄

[이]
[is]
[ㅏ]
[테스트]

BASH 3 이상에서 가장 쉽고 안전한 방법은 다음과 같습니다.

var="string    to  split"
read -ra arr <<<"$var"

(where arr is the array which takes the splitted parts of the string) or, if there might be newlines in the input and you want more than just the first line:

var="string    to  split"
read -ra arr -d '' <<<"$var"

(please note the space in -d '', it cannot be left away), but this might give you an unexpected newline from <<<"$var" (as this implicitly adds an LF at the end).

Example:

touch NOPE
var="* a  *"
read -ra arr <<<"$var"
for a in "${arr[@]}"; do echo "[$a]"; done

Outputs the expected

[*]
[a]
[*]

as this solution (in contrast to all previous solutions here) is not prone to unexpected and often uncontrollable shell globbing.

Also this gives you the full power of IFS as you probably want:

Example:

IFS=: read -ra arr < <(grep "^$USER:" /etc/passwd)
for a in "${arr[@]}"; do echo "[$a]"; done

Outputs something like:

[tino]
[x]
[1000]
[1000]
[Valentin Hilbig]
[/home/tino]
[/bin/bash]

As you can see, spaces can be preserved this way, too:

IFS=: read -ra arr <<<' split  :   this    '
for a in "${arr[@]}"; do echo "[$a]"; done

outputs

[ split  ]
[   this    ]

Please note that the handling of IFS in BASH is a subject on it's own, so do your tests, some interesting topics on this:

  • unset IFS: Ignores runs of SPC, TAB, NL and on line starts and ends
  • IFS='': No field separation, just reads everything
  • IFS=' ': Runs of SPC (and SPC only)

Some last example

var=$'\n\nthis is\n\n\na test\n\n'
IFS=$'\n' read -ra arr -d '' <<<"$var"
i=0; for a in "${arr[@]}"; do let i++; echo "$i [$a]"; done

outputs

1 [this is]
2 [a test]

while

unset IFS
var=$'\n\nthis is\n\n\na test\n\n'
read -ra arr -d '' <<<"$var"
i=0; for a in "${arr[@]}"; do let i++; echo "$i [$a]"; done

outputs

1 [this]
2 [is]
3 [a]
4 [test]

BTW:

  • If you are not used to $'ANSI-ESCAPED-STRING' get used to it, it's a timesaver.

  • If you do not include -r (like in read -a arr <<<"$var") then read does backslash escapes. This is left as exercise for the reader.


For the second question:

To test for something in a string I usually stick to case, as this can check for multiple cases at once (note: case only executes the first match, if you need fallthrough use multiplce case statements), and this need is quite often the case (pun intended):

case "$var" in
'')                empty_var;;                # variable is empty
*' '*)             have_space "$var";;        # have SPC
*[[:space:]]*)     have_whitespace "$var";;   # have whitespaces like TAB
*[^-+.,A-Za-z0-9]*) have_nonalnum "$var";;    # non-alphanum-chars found
*[-+.,]*)          have_punctuation "$var";;  # some punctuation chars found
*)                 default_case "$var";;      # if all above does not match
esac

So you can set the return value to check for SPC like this:

case "$var" in (*' '*) true;; (*) false;; esac

Why case? Because it usually is a bit more readable than regex sequences, and thanks to Shell metacharacters it handles 99% of all needs very well.


$ echo "This is   a sentence." | tr -s " " "\012"
This
is
a
sentence.

For checking for spaces, use grep:

$ echo "This is   a sentence." | grep " " > /dev/null
$ echo $?
0
$ echo "Thisisasentence." | grep " " > /dev/null     
$ echo $?
1

(A) To split a sentence into its words (space separated) you can simply use the default IFS by using

array=( $string )


Example running the following snippet

#!/bin/bash

sentence="this is the \"sentence\"   'you' want to split"
words=( $sentence )

len="${#words[@]}"
echo "words counted: $len"

printf "%s\n" "${words[@]}" ## print array

will output

words counted: 8
this
is
the
"sentence"
'you'
want
to
split

As you can see you can use single or double quotes too without any problem

Notes:
-- this is basically the same of mob's answer, but in this way you store the array for any further needing. If you only need a single loop, you can use his answer, which is one line shorter :)
-- please refer to this question for alternate methods to split a string based on delimiter.


(B) To check for a character in a string you can also use a regular expression match.
Example to check for the presence of a space character you can use:

regex='\s{1,}'
if [[ "$sentence" =~ $regex ]]
    then
        echo "Space here!";
fi

For checking spaces just with bash:

[[ "$str" = "${str% *}" ]] && echo "no spaces" || echo "has spaces"

참고URL : https://stackoverflow.com/questions/1469849/how-to-split-one-string-into-multiple-strings-separated-by-at-least-one-space-in

반응형