2016-06-16 29 views
0

ファイル名の配列を作成しようとしているので、大きなファイルを並べ替えて、必要なファイルのみを取り出すことができます。私のスクリプトは次のようになっています set STATIONS = Kanto-station-names「関東駅名」フォルダには、必要なファイル名があります。これにはmyarr=($(awk '{print $1}') $STATIONS)が続きますが、端末はすぐにサブシェルに入ります。サブシェルは、コマンドが機能せず終了できない作業ドキュメントのように見えます。助言がありますか?bash配列を修正するにはどうしたらいいですか?

+1

問題を再現するのに十分な情報が質問に含まれていることを確認してください。 –

+3

見てください:http://www.shellcheck.net/ – Cyrus

+0

...一般に、*何も*をシェル配列に読み込むには、適切なツールは 'readarray -t' /' mapfile -t'です、または少なくとも 'read -a'、またはappend操作を実行する' while'ループがあります。 'arr =($(...))'は非常に*非常に*エラーが発生しやすく、避けなければなりません。 –

答えて

0

ファイル名のリストを取得するためにfindコマンドを使用して配列を作成するだけではどうですか?

例:

#!/bin/bash 
IFS=$'\n' 
MyArr=($(find /location/to/Kanto-station-names/ -type f -print0 | xargs -0 ls)) 

echo ${MyArr[@]} 
echo ${MyArr[1} 
echo ${MyArr[2} 
echo ${MyArr[3} 
+3

どうしてですか?それは完全に壊れているので!ファイル名にスペース、改行、またはグロブ文字が含まれている場合は壊れます。 –

+0

@gniourf_gniourfあなたは絶対に正しいです。これは良いですか? – bluerojo

+1

まあ...それはまだ壊れている!あなたはまだパス名の拡張を受けています(これは 'set -f'で修正できます)。それでも改行を含むファイル名では壊れています(これはこのメソッドでは修正できません)。そのようなコマンドを解析することは、実際には常に悪い考えです。しかし、あなたが_really_(GNU) 'find'を100%安全な方法で使用したいなら、これを実行してください:' MyArr =();一方、IFS = read -r -d "ファイル。 do MyArr + =( "$ file"); done <<(find/location/to /関東駅名/ -type f -print0) 'となります。 –

0

あなたの質問は理解することは難しいですが、あなただけの関東・ステーション名のディレクトリ内のすべてのファイル名の配列を作成したい場合は、これは(仕事 "をリードすることに注意すべきです

$ echo ${myArray[0]} 
$ echo ${myArray[1]} 
:あなたは、配列の要素にアクセスすることができ、その後

$ myArray=() 
$ for FILE in `ls Kanto-station-names` ; do myArray+=($FILE) ; done 

:$」はユーザーが入力するプロンプトではなく、何か)であります

など は、配列のすべての要素を表示するには:ノートの

$ echo ${myArray[@]} 
+3

[ls'を解析しないでください](http://mywiki.wooledge.org/ParsingLs)。 –

+0

@gniourfファイル名のいずれかに空白が含まれていると、上記はうまくいきません。あなたがリンクしたその例でも、ファイル名に改行が入っていて、それは恐ろしいことです。つまり、私はいつも「ls」を何の問題もなく解析します。私は単に空白でファイルを命名しないという方針を持っています。 IMO、複数のトークンであるファイル名を持つのは悪いことです(WinやMacでは一般的に見られますが、* nixではそうではありません)。 –

+1

悪いのは、ファイル名について何かを引き受けることです。ファイル名は '/'を含まないC文字列です。期間。あなた自身が 'ls'を解析しているのであれば、間違ったことをしていることになります。つまり、シェルはどのように構文解析するのかを理解していないからです。さらに、あなたはサブシェルを生成して外部コマンドを使用していますが、それは本当に効率的ではありません。代わりにグロブを使用してください:100%安全で、タイプが短く、効率的です(それは意味的に正しいです)。 –

0
#!/usr/bin/env bash 

# cause globs to expand to an empty list if no matches exist 
shopt -s nullglob 

# Use a glob expression to populate the array 
stations=(Kanto-station-names/*) 

((${#stations[@]})) || { 
    echo "ERROR: No stations exist (make sure Kanto-station-names contains files)" >&2 
    exit 1 
} 

## read into an array (bash 4.0 or newer) 
#readarray -t myarr < <(awk '{print $1}' "${stations[@]}") 

# read into an array (bash 3.x-compatible) 
IFS=$'\n' read -r -d '' -a myarr < <(awk '{print $1}' "${stations[@]}" && printf '\0') || { 
    echo "Error extracting first column from station list" >&2 
    exit 1 
} 

# print definition of our populated array as output 
declare -p myarr 

アイテム:

  • Weこのコードにはlsを使用しないでください。すべての世代のファイル名のリストはグロビングで実行されます。 Why you shouldn't parse the output of ls(1)を参照してください。
  • "${stations[@]}"は名前がawkに渡されるので、awkを実行している内部プロセス置換を展開している - これは、元のコードのバグの一つでした。
  • bash 4.0のコメントアウトされた代替のreadarrayコードは、失敗した終了ステータスをawkから検出しません。 bash 4.4以降では、wait "$!" || { echo "Process failed" >&2; }などを実行してプロセス置換が失敗したときを検出できます。その前に、プロセス置換の終了ステータスを検出できないため、bash 3.x- bash 4.0〜4.3でも互換性のあるアプローチです。
関連する問題