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

相关内容