我经常将文件从 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