allow user to complete parallel / xargs command (function) after selecting files into array; quoting nuls correctly in printf script

你说的曾经没有我的故事 提交于 2020-02-25 04:06:50

问题


This is a follow-on question to this question

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.

The filenames can have spaces in them; hence the choice of Null-separated.

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.

Currently I have

#!/bin/bash
readarray -d '' out < <(fd .|fzf  --print0 -e -m  --expect=ctrl-e,ctrl-l)
if [ ${#out[@]} -eq 0 ]; then return 0
fi
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 ;;
* )
cmd="printf \"%s\0\" ${y[@]} | parallel -0 wc"
read -e -i "$cmd"; eval "$REPLY" ;; #not working
esac

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

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

to which I might for example, append wc

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

So something has obviously gone wrong with the nuls.

How do I fix the code?


回答1:


It is still unclear to me what you want to do. Comment your code and make sure every variable name has a name that says what it is used for.

Do you want the user to be able to enter a command and have that command run on the files in the array?

# What command does the user want to run?
# The command is a GNU Parallel command template
# So {} will be replaced with the argument
IFS= read -r command_to_run
# Run $command_to_run for every @y.
# -0 is needed if an element in @y contains \n
parallel -0 "$command_to_run" ::: "${y[@]}"

Or maybe:

# Set default command template
cmd="printf \"%s\0\" \${y[@]} | parallel -0 wc"
# Let the user edit the template
IFS= read -r -e -i "$cmd"
# Run the input
eval "$REPLY"



回答2:


Ignoring whether fzf and parallel do what you want, the following quite certainly doesn't:

cmd="printf \"%s\0\" ${y[@]} | parallel -0 wc"

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).


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"
read -e -i "$cmd" cmd_edited; eval "$cmd_edited"


来源:https://stackoverflow.com/questions/60368951/allow-user-to-complete-parallel-xargs-command-function-after-selecting-files

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!