web-dev-qa-db-ja.com

Bash配列でのパラメーター置換の使用

Bash配列に読み込む必要のあるfile.txtがあります。次に、スペース、二重引用符、およびすべてのエントリの最初のカンマを除くすべてを削除する必要があります。これが私がどこまで得たかです:

$ cat file.txt
10,this
2 0 , i s
30,"all"
40,I
50,n,e,e,d,2
60",s e,e"

$ cat script.sh
#!/bin/bash
readarray -t ARRAY<$1
ARRAY=( "${ARRAY[@]// /}" )
ARRAY=( "${ARRAY[@]//\"/}" )
for ELEMENT in "${ARRAY[@]}";do
    echo "|ELEMENT|$ELEMENT|"
done

$ ./script.sh file.txt
|ELEMENT|10,this|
|ELEMENT|20,is|
|ELEMENT|30,all|
|ELEMENT|40,I|
|ELEMENT|50,n,e,e,d,2|
|ELEMENT|60,se,e|

コンマの状況を除いて、それは素晴らしい働きをします。この猫のスキンを作成する方法は複数あることは承知していますが、これは一部のスクリプトが大きいため、ここに到達するにはパラメーター置換を使用したいと思います。

|ELEMENT|10,this|
|ELEMENT|20,is|
|ELEMENT|30,all|
|ELEMENT|40,I|
|ELEMENT|50,need2|
|ELEMENT|60,see|

これはパラメーターの置換によって可能ですか?

8
Jon Red

sedbeforeを使用して削除する必要があるものを配列にロードします(また、小文字の変数名にも注意してください。一般に、シェルスクリプトでは大文字の変数を使用しないことをお勧めします)。

#!/bin/bash
readarray -t array< <(sed 's/"//g; s/  *//g; s/,/"/; s/,//g; s/"/,/' "$1")
for element in "${array[@]}";do
    echo "|ELEMENT|$element|"
done

これにより、サンプルファイルに次の出力が生成されます。

$ foo.sh file 
|ELEMENT|10,this|
|ELEMENT|20,is|
|ELEMENT|30,all|
|ELEMENT|40,I|
|ELEMENT|50,need2|
|ELEMENT|60,see|

本当にパラメータ置換を使用する必要がある場合は、次のようなことを試してください:

#!/bin/bash
readarray -t array< "$1"
array=( "${array[@]// /}" )
array=( "${array[@]//\"/}" )
array=( "${array[@]/,/\"}" )
array=( "${array[@]//,/}" )
array=( "${array[@]/\"/,}" )

for element in "${array[@]}"; do
    echo "|ELEMENT|$element|"
done
9
terdon

私が見る限り、その出力を作成するためにbash配列に読み込む必要はありません。

$ sed 's/[ "]//g; s/,/ /; s/,//g; s/ /,/; s/.*/|ELEMENT|&|/' <file
|ELEMENT|10,this|
|ELEMENT|20,is|
|ELEMENT|30,all|
|ELEMENT|40,I|
|ELEMENT|50,need2|
|ELEMENT|60,see|

sed式は、スペースと二重引用符を削除し、最初のコンマをスペースに置き換えます(この時点では文字列に他のスペースはありません)、他のすべてのコンマを削除し、最初のコンマを復元し、先頭に追加して追加します追加データ。

または、GNU sed

sed 's/[ "]//g; s/,//2g; s/.*/|ELEMENT|&|/' <file

(標準のsedは、gコマンドへのフラグとして2sの組み合わせをサポートしていません)。

10
Kusalananda
ELEMENT='50,n,e,e,d,2'
IFS=, read -r first rest <<<"$ELEMENT"
printf "%s,%s\n" "$first" "${rest//,/}"
50,need2

ALLCAPS変数名を使用する習慣から抜け出します。最終的には、PATHなどの重要な「システム」変数と衝突し、コードを破壊します。

9
glenn jackman

[これは本質的に、より完全に開発されたバージョン glenn jackmann's answer ]です。

最初のコンマをセパレーターとして使用して、除去されたキーと値から連想配列を作成します。

declare -A arr
while IFS=, read -r k v; do arr["${k//[ \"]}"]="${v//[ ,\"]}"; done < file.txt
for k in "${!arr[@]}"; do 
  printf '|ELEMENT|%s,%s|\n' "$k" "${arr[$k]}"
done
|ELEMENT|20,is|
|ELEMENT|10,this|
|ELEMENT|50,need2|
|ELEMENT|40,I|
|ELEMENT|60,see|
|ELEMENT|30,all|
8
steeldriver

配列をループして中間変数を使用できます。

for((i=0; i < "${#ARRAY[@]}"; i++))
do
  rest="${ARRAY[i]#*,}"
  ARRAY[i]="${ARRAY[i]%%,*}","${rest//,/}"
done

これは、最初のカンマの後の部分をrestに割り当てます。次に、3つの部分を連結して元の変数に戻します。

  • 最初のカンマの前の部分
  • コンマ
  • restのすべてのカンマの置換
6
Jeff Schaller