各単語の間に少なくとも1つのスペースを入れた多数の単語を含む文字列があります。文字列を個々の単語に分割してそれらをループできるようにするにはどうすればよいですか。
文字列は引数として渡されます。例えば。 ${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配列リファレンス もご覧ください。
シェルの "set"ビルトインを使うだけです。例えば、
$ textを設定します
その後、$ text内の個々の単語は、$ 1、$ 2、$ 3などになります。
set - ジャンク$ text shift
$ textが空の場合やダッシュで始まる場合を処理します。例えば:
text = "これはテストです" set - junk $ text shift [Word]。 do echo "[$ Word]" done
この版画
[これはテストです]
BASH 3以降でおそらく最も簡単で安全な方法は次のとおりです。
var="string to split"
read -ra arr <<<"$var"
(ここでarr
name__は文字列の分割された部分を受け取る配列です)、または入力に改行があり、最初の行以上のものが必要な場合:
var="string to split"
read -ra arr -d '' <<<"$var"
(-d ''
のスペースに注意してください、それは残しておくことはできません)、しかしこれは<<<"$var"
から予期しない改行を与えるかもしれません(これは暗黙的に末尾にLFを追加するため) 。
例:
touch NOPE
var="* a *"
read -ra arr <<<"$var"
for a in "${arr[@]}"; do echo "[$a]"; done
期待どおりに出力する
[*]
[a]
[*]
このソリューションは(ここでの以前のすべてのソリューションとは対照的に)予期しない、しばしば制御不能なシェルグロビングの傾向がありません。
また、これはおそらくあなたが望むようにIFSのフルパワーを提供します:
例:
IFS=: read -ra arr < <(grep "^$USER:" /etc/passwd)
for a in "${arr[@]}"; do echo "[$a]"; done
次のようなものを出力します。
[tino]
[x]
[1000]
[1000]
[Valentin Hilbig]
[/home/tino]
[/bin/bash]
ご覧のとおり、この方法でもスペースを保持できます。
IFS=: read -ra arr <<<' split : this '
for a in "${arr[@]}"; do echo "[$a]"; done
出力
[ split ]
[ this ]
BASHでのIFS
name__の処理はそれ自体が主題であることに注意してください。テストも同様です。
unset IFS
:SPC、TAB、NLの実行を無視し、オンラインの開始と終了を無視しますIFS=''
:フィールド分離なし、すべてを読み取るIFS=' '
:SPCの実行(およびSPCのみ)最後の例
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
出力
1 [this is]
2 [a test]
ながら
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
出力
1 [this]
2 [is]
3 [a]
4 [test]
ところで:
$'ANSI-ESCAPED-STRING'
に慣れていない場合は、時間の節約になります。
-r
(read -a arr <<<"$var"
のように)を含めない場合、readはバックスラッシュエスケープを行います。これは、読者の練習問題として残されています。
2番目の質問:
文字列内の何かをテストするために、私は通常case
name__に固執します。これは複数のケースを一度にチェックできるためです(注:フォールスルーが必要な場合、caseは最初の一致のみを実行し、マルチプルcase
name__ステートメントを使用します) (しゃれ意図):
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
したがって、次のように戻り値を設定してSPCを確認できます。
case "$var" in (*' '*) true;; (*) false;; esac
なぜcase
name__ですか?通常、正規表現シーケンスよりも少し読みやすいため、シェルメタキャラクターのおかげで、すべてのニーズの99%を非常にうまく処理します。
$ echo "This is a sentence." | tr -s " " "\012"
This
is
a
sentence.
スペースをチェックするには、grepを使用します。
$ echo "This is a sentence." | grep " " > /dev/null
$ echo $?
0
$ echo "Thisisasentence." | grep " " > /dev/null
$ echo $?
1
(A)文を単語に分割する(スペース区切り)には、次のように単純にデフォルトのIFSを使用します。
array=( $string )
次のスニペットを実行する例
#!/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
出力します
words counted: 8
this
is
the
"sentence"
'you'
want
to
split
ご覧のとおり、一重引用符または二重引用符も問題なく使用できます。
注:
- これは基本的に mob の回答と同じですが、このようにして、必要に応じて配列を保存します。単一のループだけが必要な場合は、彼の答えを使用できます。これは1行短くなります。
- 区切り文字に基づいて文字列を分割する別の方法については、 この質問 を参照してください。
(B)文字列内の文字をチェックするには、正規表現の一致を使用することもできます。
あなたが使用できるスペース文字の存在をチェックする例:
regex='\s{1,}'
if [[ "$sentence" =~ $regex ]]
then
echo "Space here!";
fi
Bashだけでスペースをチェックするには:
[[ "$str" = "${str% *}" ]] && echo "no spaces" || echo "has spaces"