You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
57 lines
1.3 KiB
57 lines
1.3 KiB
#!/usr/bin/env bash
|
|
#
|
|
# usage: xargs_by_dir.sh cmd [args...] < pathnames
|
|
#
|
|
# Run a command with pathnames given over stdin, grouping pathnames by its
|
|
# dirname and supplying each invocation of the command with pathnames in the
|
|
# same directory. This is useful for commands that require all pathname
|
|
# arguments to be in the same directory, such as go generate.
|
|
|
|
set -eu
|
|
|
|
dirname() {
|
|
case "${1}" in
|
|
*/*) echo "${1%/*}";;
|
|
*) echo ".";;
|
|
esac
|
|
}
|
|
|
|
unset -v cmd ok
|
|
declare -a cmd=("${@}")
|
|
ok=true
|
|
run_cmd() {
|
|
case $# in 0) return;; esac
|
|
"${cmd[@]}" "${@}" || ok=false
|
|
}
|
|
|
|
# sort the input list by directory; replace stdin with the sorted list
|
|
unset -v sorted_list
|
|
trap 'case "${sorted_list-}" in ?*) rm -f "${sorted_list}";; esac' EXIT
|
|
sorted_list=$(mktemp)
|
|
sort -t/ > "${sorted_list}"
|
|
exec < "${sorted_list}"
|
|
|
|
unset -v last_dir dir path
|
|
set --
|
|
while read -r path
|
|
do
|
|
# dirname of the next item to consider
|
|
dir=$(dirname "${path}")
|
|
# the same dir as the last one?
|
|
case "${last_dir-}" in
|
|
"${dir}")
|
|
# same dir; do not flush the list
|
|
;;
|
|
*)
|
|
# dir change; run with items seen so far and flush the list
|
|
run_cmd "${@}"
|
|
set --
|
|
;;
|
|
esac
|
|
# add the item, update the last-seen dir for the next iteration
|
|
set -- "${@}" "${path}"
|
|
last_dir="${dir}"
|
|
done
|
|
# seen the last file; run with items seen so far
|
|
run_cmd "${@}"
|
|
${ok} && exit 0 || exit 1
|
|
|