Bashでの配列値の処理

Bashでの配列値の処理

ファイル名に基づいて配列を作成しようとしていますが、スペースに問題があります。これは非常に一般的なようです。しかし、私が知っている限り、引用符は正しく設定され、配列がどのように構成されているかを推測します。

to_dump="$(find . -maxdepth 1 -print0 )"
to_dump_array=($to_dump)

read -p " ->  " final
case "$final" in
   a) for drop in "${to_dump_array[@]}" ;
      do cp "$drop" --recursive --force Destination_Folder && \
      echo "dropped \"$drop\" ;
      done ;;
   b) echo "Won't drop anything" ;;
esac

クエリクエリで配列を作成するより良い方法があるべきだと思います。また、私はまたどこに間違っていますか?

答え1

-print0$(...)bash変数の文字列はnullで終わるため、置換に使用しないでください。

私はこの質問が尋ねるのと同じ答えで質問しました。https://stackoverflow.com/a/30469553/1091693

次の答えをあなたの質問に合わせて調整してください。

to_dump=()
while IFS= read -r -d ''; do
  to_dump+=( "$REPLY" )
done < <(find . -maxdepth 1 -print0)

その後、名前付き配列が作成され、to_dumpこのreadコマンドを使用して配列からNULLで区切られた要素を読み取りますfind。ここでパイプの代わりに使用する理由は、< <(...)配列が変更されるのを防ぐ暗黙的なサブシェルを避けるためです。

元のfindコマンドに1つが必要な場合-mindepth 1や、.再帰的にコピーする(現在のディレクトリ)を選択することができることは注目に値します。


私は-maxdepth 1findのための引数として使用したことがわかりました。おそらくこれはもっと役に立つでしょう:

shopt -s nullglob
to_dump=( * .[!.]* ..?* )

避けてくださいfind。これはbash組み込みのみを使用し、フォークせず、ほとんど非常にきれいです。

最初の行shopt -s nullglobは、このオプションを有効にするbash(-only)コマンドですnullglob。オプションは以下に説明されていますman 1 bash

設定されている場合、bashは、どのファイルとも一致しないパターン(上記のパス名の拡張を参照)を、自分ではなく空の文字列に拡張することを許可します。

簡単に言えば、入力したファイルが*ファイルと一致しない場合は削除されます*。デフォルトの動作は*、とにかくそのファイルを置くことです。

2行目は配列に3つの球を追加します。

  • *: 次から始まらないすべてのファイル.
  • .[!.]*.:1つと1つの非文字で始まるすべてのファイル.。これは一致.やディレクトリを避けるためです..
  • ..?*..: 1 つ以上の文字で始まるすべてのファイルです。これを追加する理由は前のglobと同じであり、欠落している場合が含まれます。

Bashはglobを配列定義に拡張し、正しく拡張します。スペースや同様の分割はありません。

nullglobの使用に関する警告:nullglobをオンにすると、カールは引数を渡さなかったと文句を言い、curl google.com/search?q=test現在のls /var/fasdfasafs*ディレクトリリストを提供します。これがデフォルトでオンになっていない理由の1つです。

答え2

次のように配列を作成します。

read -d $'\0' -r -a to_dump <<< $(find . -maxdepth 1 -print0)

答え3

 find . -maxdepth 1

...あなたが望むものは次のとおりです。

a=()
for f in ./..?* ./.[!.]* ./*
do  [ -e "$f" ] && a+=$f
done

答え4

あなたのスクリプトがあなたが思うように動作するかどうかはわかりません。私はこれがnullで終わるfind出力をファイル名のbash配列に変換するとは思いません。

to_dump_array=($to_dump)

forループの出力を確認して結果を確認しましたか?

for drop in "${to_dump_array[@]}"
do
    echo -e "$drop\n"
done

find -print0で配列を埋める方法に関するいくつかのアドバイスを含むスタックオーバーフローがあります。

https://stackoverflow.com/questions/1116992/capturing-output-of-find-print0-into-a-bash-array

for ループの変数に直接代入するよりも、配列項目に対して配列索引付けを使用する方が良い場合があります。これにより、適切な分割のためにシェルに頼る必要がなくなります。

for drop in $(seq 0 $((${#to_dump_array[@]} - 1)))
do
    cp "${to_dump_array[$drop]}"

これはあまり人気がないかもしれませんが、ファイル名のスペース(および他の珍しい文字)を管理するためにbash配列と複数のエスケープを使用する必要がある場合、シェルは設計された目的を超える可能性があります。

Python、Perl、Rubyなどがより高速で信頼性が高く、コードベースを管理およびデバッグするのがより簡単であることがわかります。

私はシェルスクリプトに適したレベルを超えている場合を知らせるために使用するいくつかの「リスクシグナル」を持っています。

  • すべてのファイル名の状況を処理するための複数レベルのエスケープまたはヌル終了。
  • 複数階層のシェル関数が互いに呼び出します。
  • 複雑なデータ構造つまり、文字列と数字を超えています。
  • 「性能最適化」を行っています。
  • 式の「ラインノイズ」。

はい、上記のすべての作業を確実に実行できます。しかし、そうする必要がありますか?本当に…Python、Perl、Rubyなど。 Pythonでは非常に簡単です。スペースやバイナリ文字を含むファイル名やエスケープについて心配する必要はありません。

import os

dirListing = os.listdir("somedirectory")

for eachEntry in dirlisting:
    doSomething

関連情報