Grepファイル名と選択メニューで使用

Grepファイル名と選択メニューで使用

私は多くの場合、Windows共有からローカルフォルダにファイルをコピーして貼り付けます。これには、ファイル名を検索し、この検索に基づいて選択できるメニューを持ち、選択したファイルをローカルフォルダにコピーできる小さなbashスクリプトが必要です。ローカル共有を再スキャンするには毎回時間がかかり、ファイルが頻繁に変更されないためfilelist.txt

選択メニューのさまざまなヘルプサイトからコピーして貼り付けて、次のコードを考えました。しかし、grep出力と選択メニューに問題があります。何らかの形で改行文字が認識されず、オプション#1としてすべてのファイル名のリストがあり、オプション#2が終了します。これは、スクリプトがgrep出力を他のオプションに分割しないことを意味します。

この動作を防ぐにはどうすればよいですか?私は何が間違っていましたか?この方法でgrepを使用できますか、それとも別の機能を使用する必要がありますか?

スクリプトexample_script:

#!/bin/bash
read -p 'What are you searching for?  ' file_search_name
prompt="Please select a file:"
options=$(grep $file_search_name $HOME/Local/Folder/filelist.txt)

PS3="$prompt "
select opt in "${options[@]}" "Quit" ; do 
  if (( REPLY == 1 + ${#options[@]} )) ; then
    exit

  elif (( REPLY > 0 && REPLY <= ${#options[@]} )) ; then
    echo  "You picked $opt which is file $REPLY"
    break

  else
    echo "Invalid option. Try another one."
  fi
done

cp ~/Windows/Share/"$opt" $HOME/Local/Folder/"$opt"

出力例:

$ example_script
What are you searching for?  File
1) File1.txt
File2.txt
File3.txt
...
2) Quit
Please select a file:

ベストアンサー1

grep結果を文字列ではなく配列として保存する必要があります。

options=( $(grep $file_search_name $HOME/Local/Folder/filelist.txt) )

ただし、ファイル名にスペースが含まれていると正しく機能しません。したがって、mapfile組み込み機能(help mapfile詳細を参照)を使用し、次のことも実行する必要があります。変数参照。以下はスクリプトの作業バージョンです。

#!/bin/bash
read -p 'What are you searching for?  ' file_search_name
prompt="Please select a file:"
mapfile -t options < <(grep "$file_search_name" "$HOME/Local/Folder/filelist.txt") 

PS3="$prompt "
select opt in "${options[@]}" "Quit" ; do 
  if (( REPLY == 1 + "${#options[@]}" )) ; then
    exit

  elif (( REPLY > 0 && REPLY <= "${#options[@]}" )) ; then
    echo  "You picked $opt which is file $REPLY"
    break

  else
    echo "Invalid option. Try another one."
  fi
done

何が起こっているのかを理解するには、次の例を試してください。

$ cat file
foo
bar
baz
a line with spaces

今あなたについて話しましょうgrepa

$ grep a file
bar
baz
a line with spaces

元のスクリプトのように保存すると、次のようになります。

options=$( grep a file)

これは単一の文字列です。したがって、${options[@]}対応する単一の文字列に展開すると、次のようになります。

$ for i in "${options[@]}"; do echo "Option: $i"; done
Option: bar
baz
a line with spaces

もう一度やり直して配列として保存します。

$ options=( $( grep a file) )
$ for i in "${options[@]}"; do echo "Option: $i"; done
Option: bar
Option: baz
Option: a
Option: line
Option: with
Option: spaces

これが良いです。少なくとも文字列ではなく配列ですが、見てわかるように空白をうまく処理できません。これがmapfile入ってくるところです:

$ mapfile -t options < <(grep "$file_search_name" "$HOME/Local/Folder/filelist.txt")
$ for i in "${options[@]}"; do echo "Option: $i"; done
Option: bar
Option: baz
Option: a line with spaces

配列として読み取られた-t値に、mapfile各入力行の末尾の改行文字()が含まれていないことを示します。\n

おすすめ記事