ファイル名の各文字を繰り返すには?

ファイル名の各文字を繰り返すには?

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}は内容の長さですvarprintf %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

内部ループの役割:

  • 最初の文字を減算した値に設定しますrestfname

  • 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

関連情報