私は多くの場合、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
今あなたについて話しましょうgrep
:a
$ 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