for
したがって、外部ループはディレクトリ内のすべてのファイルを繰り返し、内部ループにはfor
そのファイル名のすべての文字を繰り返す単純なネストされたループがあります。
#!/bin/bash
if [ $# -lt 1 ]
then
echo "Please provide an argument"
exit
fi
for file in `ls $1`
do
for ch in $file
do
echo $ch
done
done
上記のスクリプトは機能しません。内部ループは、ファイル名のすべての文字を繰り返すのではなく、内容全体を繰り返します。
修正する:
@ilkkachuの答えに基づいて、次のスクリプトを思いつくことができ、期待どおりに動作します。しかし、for...in
ループを使わずに文字列を繰り返すことができるかどうか疑問に思います。
#!/bin/bash
if [ $# -lt 1 ]
then
echo "Please provide an argument"
exit
fi
for file in `ls $1`; do
for ((i=0; i<${#file}; i++)); do
printf "%q\n" "${file:i:1}"
done
done
答え1
Bashを使っているので:
#!/bin/bash
word=foobar
for ((i=0; i < ${#word}; i++)); do
printf "char: %q\n" "${word:i:1}"
done
${var:p:k}
与えられたKvar
場所から始まる文字血、${#var}
は内容の長さですvar
。printf %q
明示的な形式で出力を印刷します$'\n'
。たとえば、改行文字は 。
答え2
文字列が数百文字を超える場合(たとえば、ファイル名の場合は可能ではありません)、文字列の長さにforループを使用してインデックスから文字を抽出するのはi
非常に遅くなります。
この答えは高度なbash技術を使用します。
while IFS= read -r -d "" -n 1 char; do
# do something with char, like adding it to an array
chars+=( "$char" )
done < <(printf '%s' "$string")
# inspect the array
declare -p chars
これはプロセスの交換文字列の読み込み中にループにリダイレクトします。私はprintf
文字列の末尾に改行文字を追加することを避けるために使用します。プロセス置換を使用する主な利点printf ... | while read ...
は、ループが発生することです。現在のシェルではなく息子シェル。
私は遅い程度について疑問に思いました。ベンチマーク。
答え3
完全性のために質問にタグ付けされていても強く打つ、POSIXシェル機能のみを使用する代替案:
#!/bin/sh
for fname
do
while [ "${#fname}" -ge 1 ]
do
rest=${fname#?} char=${fname%"$rest"} fname=$rest
printf '%s\n' "$char" # Do something with the current character
done
done
内部ループの役割:
最初の文字を減算した値に設定します
rest
。fname
rest
削除された単一文字をに割り当てfname
ますchar
。fname
の値に設定rest
し、すべての文字が処理されるまで繰り返します。
拡張がパターンとして使用されるのを${fname%"$rest"}
防ぐために、引用符を使用してください。$rest
ところで、for file in `ls $1`
避けるべきです。最も明白な理由は、ファイル名にIFS
。バッシュトラップ1、何をすべきかを含みます。
答え4
bash
文字列分割演算子を使用します。
s="string"
for c in $(seq 0 $((${#s}-1))); do echo "${s:c:1}"; done
s
t
r
i
n
g
あなたに適用されるスクリプトは次のとおりです。
#!/bin/bash
for f in *; do
echo "Char in $f:"
for i in $(seq 0 $((${#f}-1))); do
echo "${f:i:1}"
done
done