2016-05-24 7 views
0

ユーザーの入力を読み取るbashスクリプトを作成しようとしています(ユーザーがTABを使用できるようにする)。Bash:スペースに分割されてエスケープされたスペースにはない

#/bin/bash 
read -e files 
for file in $files 
do 
    echo $file 
    cp "$file" folder/"$file" 
done 

それはのために大丈夫だ:file1 file2 ...

かと:file*(フォルダ内のスペースを持つファイル名が存在する場合であっても)。

しかし、バックスラッシュでエスケープされたスペースのあるファイル名では、\のようには機能しません。file\ with\ spaceエスケープスペースは無視され、各スペースで文字列が分割され、エスケープさえさえなります。

quoting、printf、IFS、read、whileの情報を見ました...私は基本的なbashスクリプトだと思いますが、良い解決策を見つけることはできません。手伝って頂けますか?文字列がどちらかに分割されます:あなたが引用どのように関係なく動作しません単一の文字列に読み込む

read -e -a files 
for file in "${files[@]}"; do 
    echo "$file" 
    cp "$file" folder/"$file" 
done 

+0

その他:UNIXのスペルは「ディレクトリ」であり、「フォルダ」ではありません。 –

+0

'$ files'を引用するだけではいかがですか?(例えば、" $ files "のファイル)? –

+0

@ l'L'l、これはOPが明示的に望むグロブを無効にするためです。 –

答えて

3

は、文字列分割を防止しながら進めることグロブできるようになります:私たちは引用符で囲まれていない空白が扱われることを保証read動作中にデフォルトIFS=$' \t\n'を施行している

IFS=$' \t\n' read -e -a globs # read glob expressions into an array 
IFS='' 
for glob in "${globs[@]}"; do # these aren't filenames; don't claim that they are. 
    files=($glob)    # expand the glob into filenames 

    # detect the case where no files matched by checking whether the first result exists 
    # these *would* need to be quoted, but [[ ]] turns off string-splitting and globbing 
    [[ -e $files || -L $files ]] || { 
    printf 'ERROR: Glob expression %q did not match any files!\n' "$glob" >&2 
    continue 
    } 

    printf '%q\n' "${files[@]}" # print one line per file matching 
    cp -- "${files[@]}" folder/ # copy those files to the target 
done 

注意その段階で配列要素間のセパレータとして使用します。後でfiles=($glob)で、これとは対照的に、IFS=''があるので、空白で個々の名前を分割することはなくなりました。

+0

この回答をいただきありがとうございます。 – Lucien

0

あなたは配列の要素の上に、その後、ループ配列にファイル名を読み取ることができます各スペース(クォートされていない場合)または全く(クォートされている場合)詳細はthis canonical Q&Aを参照してください(あなたのケースはリストの最後の項目です)。

これはグロブを防止します。つまり、file*は展開されません。これを考慮に入れたソリューションについては、Charles' answerを参照してください。前あなたの引用符で囲まれていない展開にIFSをクリア

+0

ありがとうございました!しかし、 'file *'はもう働きません。 'file *'という名前のファイルの 'file'で始まるすべてのファイルをループしません。私はこの種の入力を許可したいと思います。 – Lucien

1

ファイルとグロブには完全に機能するソリューションがあります。

xargs(引用符で囲まれた文字列を保持することができる)の助けを借りて。しかし、あなたは、引用符の内側にスペースを含むファイルを記述する必要があります。

"file with spaces" 

スクリプトを使用する場合:UNQUOTE読み取りをしてlistOfFilesのための割り当てを引用します。

私はまた、@CharlesDuffy(チャールズさんに感謝)の投稿にいくつかのアイデアを利用しています。

#!/bin/bash 

# read -e listOfFiles 
listOfFiles='file1 file* "file with spaces"' 

IFS='' 
while IFS='' read glob; do  # read each file expressions into an array 
    files=($glob)    # try to expand the glob into filenames 

    # If no file match the split glob 
    # Then assume that the glob is a file and test its existence 
    [[ -e $files || -L $files ]] || { 
     files="$glob" 
     [[ -e $files || -L $files ]] || { 
      printf 'ERROR: Glob "%q" did not match any file!\n' "$glob" >&2 
      continue 
     } 
    } 

    printf '%q\n' "${files[@]}" # print one line per file matching 
    cp -- "${files[@]}" folder/ # copy those files to the target 
done < <(xargs -n1 <<<"$listOfFiles") 
+0

シェルがデフォルト設定になっているときに、余分なコードが何かを成し遂げているかどうかはわかりません - 一致しないグロブは、自身が評価され、 'nullglob'がアクティブでなければ評価されます。上記の回答にバグが修正された場合の例を教えてください。 –

+0

@CharlesDuffy最後の行のために: 'xargs -n1 <<<" $ listOfFiles "'二重引用符で囲まれた部分はスペースで区切られていないシェルの1行として表示されます。一度それが一行になったら、行がグロブであるかどうか、あるいはファイルであれば失敗したかどうかをテストできます。あなたの答えは、与えられたリスト(ここではスクリプト内のコードで書かれています)に空白を含むファイルがある場合を許可も処理もしません。その違いを説明できることを願っています。バグではありません:私はそれが改善であることを願っています。 –

+1

ああ、持っています。うん、私は 'file \ with \ spaces'しかサポートしていないので、これは本当に改善点です。 –

関連する問題