Reputation: 2287
I would like to apply a commands to files in a directory, target_dir, by the following code.
for t_file in $(find 'target_dir' -maxdepth 1 -type f);
do
exec {fd}<'command_list.txt'
while read -u "${fd}" eval_command
do
eval "${eval_command}"
done
exec {fd}>&-
done
A example of command_list.txt is
# command_list.txt
cat "${t_file}"
The program loads the command_file.txt for every files but I expects that it is more efficient if I can move the file pointer back to the first line of the file without needing to close and reopen it between iterations.
exec {fd}<'command_list.txt'
for t_file in $(find 'target_dir' -maxdepth 1 -type f);
do
(move cursor of read to the first line of 'command_list.txt')
while read -u "${fd}" eval_command
do
eval "${eval_command}"
done
done
exec {fd}>&-
Is seeking a file pointer back to the beginning of a file without reopening it possible in bash?
Upvotes: 0
Views: 151
Reputation: 295472
To answer the literal question: You can seek a file descriptor in bash only with a loadable module (plugin) to the shell adding a new builtin, or by spinning up an external program (inheriting your file descriptors) and asking it to do the seek operation (an approach given in this answer). However, the cost of spinning up an external program is larger than the cost of just closing and reopening your file, so that's not approach that really makes sense in this case.
If you want to store your command list, just do that -- store it as an array. If by "moving the cursor" you're referring to seeking within the input file, bash doesn't provide a seek primitive in the default set of builtins -- but there's no particular need for one anyhow.
# read command_list.txt only once, storing its contents in an array
readarray -t eval_commands < command_list.txt
while IFS= read -r -d '' t_file <&3; do # iterate over filenames from find
for eval_command in "${eval_commands[@]}"; do # iterate over your array
eval "$eval_command"
done
done 3< <(find target_dir -maxdepth 1 -type f -print0)
By the way -- if you were going to pass your filename as an argument to the command rather than substituting it in, you'd want to do so as follows:
# put the filename expansion in *single quotes*
eval "$eval_command "'"$t_file"'
...or as follows:
# generate a safe version of the filename
printf -v t_file_q '%q' "$t_file"
# ...and use that safe version instead of the original
eval "$eval_command $t_file_q"
If one ran eval "$eval_command $t_file"
-- not following either of these precautions -- a file in created with touch $'target_dir/hello world $(rm -rf $HOME)'
would be very bad news.
Upvotes: 2
Reputation: 581
find 'target_dir' -maxdepth 1 -type f -exec cat {} \;
That would cat every file in the target directory 1 folder deep.
Upvotes: 0