
У меня есть bash-скрипт под названием findme
, который закодирован следующим образом:
#!/bin/bash
locate -Abi '*\.'$1 $2 | grep --color=always -ni $2 | less -R
Он ищет для меня все файлы с указанным расширением файла (первый аргумент, предоставленный скрипту), которые имеют шаблон (следующий предоставленный аргумент) в своем имени файла.
Если я выполняю следующее:
user@machine$ findme pdf classifi
Он будет искать все pdf
файлы, содержащие classifi
в своем имени. Так что я могу получить что-то вроде следующего результата.
1:/home/user/Dropbox/SharedWithFriends/math/классификацияcations2000.pdf
2:/home/user/Dropbox/SharedWithFriends/math/классификациякатионы2010.pdf
Вопрос в том: «Можете ли вы дать мне код bash-скрипта, который после отображения результатов запросит у меня номер и средство просмотра, чтобы автоматизировать мою следующую задачу?»
например, я хотел бы, если я введу:
> 2 evince
скрипт выполняется evince
для 2
второго элемента результата поиска,то есть, если это то, что я ввел в предыдущем результате поиска, он выполнит:
evince /home/user/Dropbox/SharedWithFriends/math/classifications2010.pdf
решение1
Вот вариант вашей findme
функции, которая извлекает результаты, но вместо того, чтобы использовать grep
их для нумерации или less
разбиения на страницы, она перечисляет их из внутреннего массива, а затем запрашивает ваш выбор элемента и программы.
#!/usr/bin/env bash
readarray -O 1 -t results < <(locate -Abi '*\.'"$1" "$2" | grep --color=always -i "$2")
for((i=1; i <= ${#results[*]}; i++))
do
printf "%d: %s\n" $i "${results[i]}"
done
read -p "> " item program
$program "${results[item]}"
Я добавил кавычки в ваш оригинальный скрипт, чтобы лучше справляться с пробелами в именах файлов или даже с параметрами grep. Я отрегулировал вызов readarray
так, чтобы результаты начинались с индекса 1 вместо 0, чтобы это соответствовало нумерации grep.
решение2
Обратите внимание, что в вашем findme
скрипте есть несколько проблем:
- Отсутствуют двойные кавычки вокруг подстановок переменных
- Вывод
grep --color=always
дает результаты, которые нельзя использовать в подстановке команды. Он нужен для передачиless
, но не пытайтесь повторно использовать его в скрипте. - grep и locate используют разный синтаксис шаблонов, поэтому использование
grep
to color второго аргумента не всегда будет работать. Передача-r
tolocate
заставляет его использовать регулярные выражения, но с синтаксисом Emacs, который немного отличается от синтаксиса, поддерживаемого grep.
В bash вы можете использоватьmapfile
чтобы надежно запихнуть несколько строк в массив. Объедините это сзамена процессаиспользовать вывод команды. Затем распечатать этот массив и прочитать ввод пользователя.
findrun () {
mapfile search_hits <(locate -Abir ".*\.$1" "$2")
print '%s\n' "${search_hits[@]}" | grep --color=always -ine "$2"
if read -a cmd; then
set -- "${cmd[@]}"
set -- "$@" "${search_hits[$1]}"
shift
"$@"
fi
}
Альтернативный интерфейс — установить позиционные параметры. Это немного сложно, потому что вы не можете изменить позиционные параметры из функции, но естьокольный путь сделать это в bashиспользуя псевдоним и источник сценария. Остерегайтесь цитирования.
alias findrun='. <(echo findrun_prepare \"\$@\"; echo set -- "\"\${search_hits[@]}\"")'
findrun_prepare () {
mapfile search_hits <(locate -Abir ".*\.$1" "$2")
print '%s\n' "${search_hits[@]}" | grep --color=always -ine "$2" >&2
}
Использование:
findrun pdf classifi
evince "$2"
решение3
На основе Решения, данного Джеффом Шаллером. Я нашел решение, буду рад получить ваши комментарии, чтобы сделать его лучше.
#!/bin/bash
readarray -O 1 -t results < <(locate -Abi '*\.'"$1" "$2")
for((i=1; i <= ${#results[*]}; i++))
do
printf "%d: %s" $i "${results[i]}" | grep --color=always -i "$2"
done
read -p "> " item program
$program "${results[item]}"
Это выглядит как простой (в зависимости от сложности темы) ответ.
Но не достаточно хорошо, если результаты будут больше определенного числа! В этом случае нам нужно что-то вроде more
илиless