web-dev-qa-db-ja.com

IFSを別の値に設定してアレイを作成する

配列を作成してこの形式でファイルに書き込もうとしています。つまり、ファイルの内容は次のようになります。

_hero_pairscore=( askdjfh sdf,sdlkfj lksf,dfgdf,dsflkgj,asdlkf ....)
_

要素がcommaで区切られている場合。私はこれのために次のコードを書きました。

_#!/bin/bash
#set -x

hero_pairscore=()
while read line
do

$( IFS=",";hero_pairscore+=( "$line" )
done < true_pairscore.txt

echo "hero_pairscore=( ${hero_pairscore[@]} )" > embed.txt
_

ただし、結果のファイルにはこのhero_pairscore=( )のみが含まれます。コードの何が問題になっていますか?また、コードを修正して目的の出力を得るにはどうすればよいですか?

5
Ashwin

ここで行う必要があるのはこれだけです:

  1. 変数を設定します。これを使用します:

    var="kijhg, fbjhku,,,ioy  fbjfr, kjmyhg"
    
  2. $IFSを設定し、ファイル名の拡張を防ぎます。

    IFS=, ; set -f
    
  3. setシェル$@arrayを出力します。

    set -- $var
    
  4. 親シェル$IFSとシェルパラメータをリセットします。

    unset IFS ; set +f
    
  5. やったー!複数のリピートやスペースなどすべてを保持します。

    printf %s\\n "$@"
    

    出力

    kijhg
     fbjhku
    
    
    ioy  fbjfr
     kjmyhg
    

とにかく、私の言葉を信じてください。 ,ではないすべての文字が保持されます。

変換

スプリッターを即座に変換できるため、bash配列ではなく実際のシェル配列を使用することを特にお勧めします。

printf %s "$*"

#OUTPUT#
kijhg  fbjhku   ioy  fbjfr  kjmyhg %

IFS=, ; printf %s "$*"

#OUTPUT#
kijhg, fbjhku,,,ioy  fbjfr, kjmyhg

$*には、$IFSの最初の文字でシェルの位置パラメーター引数配列を分割するというPOSIXで指定された特別な品質があるため、データのスワスをそれと同じくらい簡単に変換できます。引数配列を"quote"-保護し、それでも好きな単一の文字に分割することができます。あなたが最初にそれを正しく理解する限り、それはです。

追加/追加

POSIXは、"$@"に特別な品質も指定します。各引数の"$1"... eval "\${$#}"アドレス指定フォームを除いて、"$@"パラメータ(引用されている場合)は、$IFS.の現在の値に関係なく、最後のsetであったため、シェルのすべての引数に安全に展開されます。したがって、リストを追加する場合配列の先頭まで:

set -- $list "$@"

頭/尻尾へ:

set -- $head "$@" $tail

配列を3倍にするには:

set -- "$@" "$@" "$@"

ALTOGETHER NOW

データストリームが非常に大きい場合を除いて、以下は現在の操作よりも少し速いかもしれません(ただし、ファイルを操作している場合は、シェル分割を完全に回避する方がはるかに良いでしょう。 )

( set -f -- ; IFS=, ; while read -r line ; do set -- "$@" $line ; done
printf %s "$*" ) | cat >out

MAYBE TR?

私が理解していないのはこれです-あなたは何をしているのですか?改行をコンマに置き換えようとしていますか?つまり---改行だけを除いてデータはすでにコンマで区切られていますか?もしそうなら:

tr '\n' ',' <in >out
6
mikeserv

私がやろうとしていることを行うにはthink _true_pairscore.txt_のすべてのコンマ区切りフィールドを配列変数に読み込みます。コードに大きな問題はありません。 IFS行の先頭にある_$(_は明らかに間違っており、スクリプトでエラーが発生します(これが出力が得られない理由である可能性があります)。それ以外の場合、コードの主な修正は、bashIFSの周りの単語分割を実行させたいので、_$line_の周りの引用符を削除することです(通常、これはあなたが使用するものです)避けるべきもの):

_#!/bin/bash

set -o noglob
OIFS=$IFS
IFS=","
hero_pairscore=()

while IFS= read -r line
do
  hero_pairscore+=( $line )
done < true_pairscore.txt

echo "hero_pairscore=( ${hero_pairscore[@]} )" > embed.txt

set +o noglob
IFS=$OIFS
_

ただし、上記を2行だけで実行するための秘訣は次のとおりです。

_IFS=$',\n' read -ra hero_pairscore -d '' <true_pairscore.txt
echo "hero_pairscore=( ${hero_pairscore[@]} )" > embed.txt
_

更新

_embed.txt_ファイルを別のbashシェルで取得する場合は、記述された_hero_pairscore_配列の各要素を引用することをお勧めします。これを行うには、echo "hero_pairscore=( ${hero_pairscore[@]} )"を次のように置き換えます。

_echo "hero_pairscore=( $(printf '"%s" ' "${hero_pairscore[@]}") )"
_
5
Graeme