选择文件到数组后,允许用户完成parallel/xargs命令(功能);在printf脚本中正确引用nul [英] allow user to complete parallel / xargs command (function) after selecting files into array; quoting nuls correctly in printf script
问题描述
这是在这个问题中,我可以将选定的文件放入数组中,并将它们传递给命令/函数(已导出).这个问题的不同之处在于,我希望用户在选择文件后完成命令.
In that question, I could get selected files into an array and pass them to a command / function (already exported). This question differs in that I would like the user to complete the command after selecting the files.
主要目的:向我展示一个文件名列表(FZF).我手动选择其中一些.然后FZF将此子集放入数组.然后,我想编写一条未完成的命令,希望用户完成该命令并按Enter
.
Main Aim: I am presented with a list of filenames (FZF). I manually select some of these. FZF then puts this subset into an array. I then want to compose an unfinished command which expects the user to complete the command and press Enter
.
文件名中可以有空格;因此选择以Null分隔.
The filenames can have spaces in them; hence the choice of Null-separated.
我正在使用FZF
选择文件.我认为它会生成一个包含无尾文件名的数组.但是FZF
产生的第一项是按键的名称.这就是为什么脚本将FZF
输出的第一项不同对待的原因.
I'm using FZF
to select the files. It produces an array containing nul-ending filenames, I think. But the first item that FZF
produces is the name of a key-press. That's why the script treats the first item of FZF
's output differently.
当前我有
#!/bin/bash
readarray -d '' out < <(fd .|fzf --print0 -e -m --expect=ctrl-e,ctrl-l)
if [ ${#out[@]} -eq 0 ]; then return 0
fi
declare -p out
key="$out"
y=${out[@]:1}
if [ ${#y[@]} -eq 0 ]; then return 0
fi
case "$key" in
ctrl-e ) echo do something ;;
ctrl-l ) echo do something else ;;
* )
printf -v array_str '%q ' "${y[@]}"
cmd="printf '%s\0' ${array_str} | parallel -0 wc"
read -e -i "$cmd" cmd_edited; eval "$cmd_edited" ;; #not working
esac
我已经接近了:该命令看起来应该正确,但是NUL值却不起作用.
最后一行不起作用.它旨在将文件数组打印在具有空分隔符的行上,并且仍然允许用户在单击Enter
之前指定一个函数(已导出). parallel
命令会将功能应用于数组中的每个文件.
I have gotten close: the command looks like it should, but the NUL values are not behaving.
The last line doesn't work. It is intended to print the array of files on a line with null separator and still allow the user to specify a function (already exported) before hitting Enter
. The parallel
command would apply the function to each file in the array.
$ls
file 1
file 2
...
...
file 100
当前,如果我选择file 3
和file 2
,则脚本的输出如下所示:
Currently, if I choose file 3
and file 2
, the output of my script looks like this:
printf "%s\0" file 3 file 2 | parallel -0
后面附加wc
但是在我键入wc
并按Enter
之后,我得到以下结果:
But then after I type wc
and press Enter
I get the following result:
printf "%s\0" file 3 file 2 | parallel -0 wc
wc: file030file020: No such file or directory
编辑:我现在加入了declare -p out
行,以明确FZF在生产什么.
现在出现的结果,使用下面的Charles修改:
Edit: I have now included the line declare -p out
to make clear what FZF is producing.
The results as they now appear, using Charles' modification below is:
declare -a out=([0]="" [1]="file 3" [2]="file 2" [3]="file 1")
printf '%s\0' file\ 3\ file\ 2\ file\ 1 | parallel -0 wc
wc: file030file020file010: No such file or directory
因此,nul显然出了问题.
So something has obviously gone wrong with the nuls.
如何修复代码?
推荐答案
忽略fzf
和parallel
是否满足您的要求,以下内容肯定不会:
Ignoring whether fzf
and parallel
do what you want, the following quite certainly doesn't:
cmd="printf \"%s\0\" ${y[@]} | parallel -0 wc"
为什么?因为${y[@]}
不会插入使y
数组的内容表示为有效的shell语法所必需的引号和转义符(当通过eval
进行反馈时引用数据的原始内容).
Why? Because ${y[@]}
doesn't insert quoting and escaping necessary to make the contents of the y
array be expressed as valid shell syntax (to refer to the data's original contents when fed back through eval
).
如果要将数据插入要解析为代码的字符串中,则需要先对其进行转义. Shell可以使用printf %q
:
If you want to insert data into a string that's going to be parsed as code, it needs to be escaped first. The shell can do that for you using printf %q
:
printf -v array_str '%q ' "${y[@]}"
cmd="printf '%s\0' ${array_str} | parallel -0 wc"
IFS= read -r -e -i "$cmd" cmd_edited; eval "$cmd_edited"
这篇关于选择文件到数组后,允许用户完成parallel/xargs命令(功能);在printf脚本中正确引用nul的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!