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| 

これはパラメータ置換を介して可能ですか?

コメント

  • テキストを保持する必要がある理由はありますか配列、および'できない理由awkまたはsedはデータの処理を行いますか?
  • @ Jeff-配列をループするとより大きなスクリプトで実装する悪夢私は'作業中です。
  • @JonRed私は'何を知りませんあなたがやっているので、'問題に選択肢がない可能性は十分にありますが、一般的に、シェルでそのような複雑な文字列のアクロバットをしていることに気付いたときは、'は、実際のプログラミング言語を使用する必要があることを示す非常に良い兆候です。シェルはプログラミング言語として設計されておらず、1つとして使用することはできますが、'より複雑なものには適していません。 perl、python、またはその他のスクリプト言語への切り替えを検討することを強くお勧めします。
  • @terdon It 'おかしいですが、ほぼ正確に言って終わりました。この投稿を読む前に、同僚にも同じことをしました。私は基本的に、これがこのスクリプトの最終バージョンであり、それ以上の要件がある場合はPerlで書き直す必要があると述べました。そうです、私は間違いなく同意します

回答

sed 配列にロードする前(小文字の変数名にも注意してください。一般に、シェルスクリプトでは大文字の変数を避けるのが最善です):

#!/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 

コメント

  • @JonRedパラメータ付きのバージョンを追加しました置換しますが、'は複雑で、面倒で、醜いです。シェルでこの種のことを行うことは、めったに良い考えではありません。
  • 'スペースと二重引用符の両方を削除すると、これらの文字が使用可能になることに注意してください。 RANDOMTEXTTHATWILLNEVERBEINTHEFILEの代わりに使用します。
  • @Kusalanandaええ、私はあなたの答えを読みました。そのことを考えるべきだった!ありがとう:)
  • 質問に直接答え、私の好みのソリューションが'理想的ではない理由を説明し、最も実行可能な代替案を提供します。あなたが勝ちます、ベストアンサー。

回答

私が見る限り、する必要はありません。これを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は、iv id = “0501c55813″のフラグとして、2gの組み合わせをサポートしていません。 >

コマンド)。

コメント

  • GNU sedでは、's/,//2gを使用できます。カンマを削除するには、 2番目から開始
  • そして、最後の2つのs ///コマンドはs/.*/|ELEMENT|&|/しかし、それはsedにとってもっと手間がかかるかもしれません。
  • @glennjackmanおそらく、しかしそれはかなりきれいに見えます。
  • ええ、これはより大きなスクリプトの一部です。配列は、出力だけでなく必要です。したがって、パラメータ置換に興味があります。これで配列をループすることもできますが、実装するのは悪夢です。 Terndonは、sedを使用したループのないソリューションを提供しました。これにより、'は、パラメーターの置換が失敗した場合にフォールバックする可能性があります。 = “fb841fb5b8″>

配列の使用に結び付けられていますが、これが最善の解決策です。

回答

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

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

コメント

  • パラメーターの置換ではありません。しかし、ALLCAPS変数名がBashの悪い習慣であることに気づいていませんでした。あなたは良い点を指摘します、それは大雑把なグーグルが間違いなく確認するものです。私のスタイルを改善してくれてありがとう! 🙂
  • '人がPATH=something; ls $PATHと書いた後、ls: command not foundエラー。
  • すべて大文字で名前が付けられた組み込み変数が100近くあります(このmanページをクリックしてくださいリンク)を見る…

回答

[これは本質的により完全に開発されたものです glennjackmannの回答のバージョン]

最初のコンマを区切り文字として使用して、削除されたキーと値から連想配列を作成します。

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| 

回答

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

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

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

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

コメント

  • これは私の最初の考えであり、例としては十分に単純ですが、これは配列が大きく、'がすでにループしている、より大きなスクリプトの一部であり、すべてです。これは間違いなく機能しますが、私が取り組んでいる'プロジェクトで実装するのは非常に面倒です。
  • 十分に公平です。制限内で答えようとしました(パラメーター拡張のみ)。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です