各単語の間に少なくとも1つのスペースがある多くの単語を含む文字列があります。文字列を個々の単語に分割して、それらをループできるようにするにはどうすればよいですか?
文字列は引数として渡されます。例えば${2} == "cat cat file"
。どうすればループできますか?
また、文字列にスペースが含まれているかどうかを確認するにはどうすればよいですか?
各単語の間に少なくとも1つのスペースがある多くの単語を含む文字列があります。文字列を個々の単語に分割して、それらをループできるようにするにはどうすればよいですか?
文字列は引数として渡されます。例えば${2} == "cat cat file"
。どうすればループできますか?
また、文字列にスペースが含まれているかどうかを確認するにはどうすればよいですか?
回答:
文字列変数をfor
ループに渡してみましたか?たとえば、bashは空白で自動的に分割されます。
sentence="This is a sentence."
for word in $sentence
do
echo $word
done
This
is
a
sentence.
A=${A}${word})
。
touch NOPE; var='* a *'; for a in $var; do echo "[$a]"; done
出力(読みやすさのためにSPCでLFが置き換えられます)[NOPE] [a] [NOPE]
[*] [a] [*]
個々の要素にアクセスできるように、配列への変換が好きです。
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配列リファレンス」も参照してください。
touch NOPE; var='* a *'; arr=($var); set | grep ^arr=
出力arr=([0]="NOPE" [1]="a" [2]="NOPE")
arr=([0]="*" [1]="a" [2]="*")
組み込みの「set」シェルを使用するだけです。例えば、
$ textを設定
その後、$ textの個々の単語は$ 1、$ 2、$ 3などになります。堅牢性のために、通常は
セット-ジャンク$ text シフト
$ textが空の場合やダッシュで始まる場合に対処します。例えば:
text = "これはテストです" セット-ジャンク$ text シフト 一言; 行う エコー "[$ word]" 終わった
これはプリント
[この] [は] [a] [テスト]
awk
たset
が、はるかに簡単です。私は今set
ファンボーイです。@Idelicに感謝!
touch NOPE; var='* a *'; set -- $var; for a; do echo "[$a]"; done
出力します。 分割された文字列にSHELLメタ文字がないことが101%わかっている場合にのみ使用してください。[NOPE] [a] [NOPE]
[*] [a] [*]
set -f
前set -- $var
とset +f
後で無効グロブへ。
set -f
あなたのソリューションも安全です。しかしset +f
、これは各シェルのデフォルトです。したがって、他の人はおそらくそれを認識していないので(私もそうでした)、これは重要な詳細であり、注意する必要があります。
BASH 3以降でおそらく最も簡単で安全な方法は次のとおりです。
var="string to split"
read -ra arr <<<"$var"
(arr
文字列の分割された部分を取得する配列です)または、入力に改行が含まれている可能性があり、最初の行だけではない場合:
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 ]
IFS
BASH でのの処理はそれ自体がテーマであるため、テストを行ってください。これに関する興味深いトピックがいくつかあります。
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
は複数のケースを一度にチェックできるため(通常、caseは最初の一致のみを実行し、フォールスルーがmultiplce case
ステートメントを使用する必要がある場合)、この必要性がよくあるケースです(pun意図されました):
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
?通常、正規表現シーケンスよりも少し読みやすく、シェルメタキャラクターのおかげで、すべてのニーズの99%を非常にうまく処理します。
set -f
またはset -o noglob
を使用して、シェルのメタ文字がこのコンテキストで害を及ぼすことがないように、グロビングを切り替えることができます。しかし、私は実際にはその友人ではありません。これはシェルの多くのパワーを残しているため、この設定を切り替えるとエラーが発生しやすくなります。
;&
達成するために使用できます。登場したbashのバージョンがよくわからない。私は4.3ユーザーです
;;&
あなたがコメントする前に知りませんでした :Dありがとう、そしてシェルがあなたと一緒にいるかもしれません;)
$ 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
echo "X" |
通常<<<"X"
、次のようにに置き換えることができますgrep -s " " <<<"This contains SPC"
。とecho X | read var
は対照的に何かをすると、違いを見つけることができますread var <<< X
。後者のみ輸入変数var
第一の変形でそれにアクセスする一方で、現在のシェルに、次のことを行う必要があり、このようなグループ:echo X | { read var; handle "$var"; }
(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"