IFSを使用して文字列を文字に分割し、スペース/ヌル、スペース、および文字なしで読み取る方法 - ?

IFSを使用して文字列を文字に分割し、スペース/ヌル、スペース、および文字なしで読み取る方法 - ?

私はロープを持っています-w o rd。重要ではないので、配列または配列に分割
する必要があります。私は次を試しました w o r d'w' 'o' 'r' 'd'

IFS='\0- ' read -a string <<< "-w o rd"  
echo ${string[*]}

rd分けられませんでした。どうやって作ることができますか?

答え1

IFSを使用してbashで何も分割することはできません(持つrd の間には文字がありませんrd。スペースや文字はヌル文字と変わりません。

各文字を配列の別々の要素として望む場合、私が考えることができる1つの方法は、各文字を個別に読み込み、それを配列に追加することです(そしてIFSを使用してスペースと削除する-)。

bash-4.4$ while IFS=' -' read -n1 c ; do [[ -n $c ]] && foo+=("$c"); done <<<"-w o rd"
bash-4.4$ declare -p foo
declare -a foo=([0]="w" [1]="o" [2]="r" [3]="d")

答え2

以下を使用して、不要な文字を削除できます${var//pattern/replacement}

s='-w o rd'
s=${s//[- ]}

次に、サブストリング拡張を使用して一度に1文字を選択します。

$ for ((i=0; i < ${#s}; i++)); do
      echo ${s:i:1};           # or do whatever you like here
  done

(少なくとも私のシステムではマルチバイト文字も処理しているようです。)


バックスラッシュは一重引用符の中に特別な意味がないため、IFS='\0- 'リテラルバックスラッシュが割り当てられます。IFS8進エスケープはBashで動作します$'...'が、Bashの変数にはNULバイトを含めることができないため、役に立ちません。 (文字列はNULで切り捨てられてx=$'foo\0bar'; printf "%q\n" "$x"印刷されますfoo。また、@muruが言うように、NULバイトに分割することは、各文字間の分割と同じではありません。)

答え3

文字列が長すぎない場合:

w='-w o rd baa'
w=${w//[!a-z]}  # strip anything but lower case letters
eval echo '${w:'{0..10}':1}'
eval array=\( '${w:'{0..10}':1}' \)
echo "${array[@]}"

w o r d b a a

zsh愚かなものをはるかに悪いもの、IFSとglobの安全性に変えることができbashますksh

args(){ printf '<%s> ' "$@"; echo; }
w='-e a * () \n peek
    fo*"x'"'q"
eval eval args "'\"\${w:'{0..$((${#w}-1))}':1}\"'"
eval eval 'array=\(' "'\"\${w:'{0..$((${#w}-1))}':1}\"'" '\)'
args "${array[@]}"

<-> <e> < > <a> < > <*> < > <(> <)> < > <\> <n> < > <p> <e> <e> <k> <
> <     > <f> <o> <*> <"> <x> <'> <q>    

しかし、正直に言うと、このモンスターの唯一の目的は、おそらくシェル言語の詳細についての深い知識を想定して初心者を恐れて愚か者に深い印象を残すことです;-)

関連情報