Как возможно выполнить команду с неизвестным количеством аргументов в оболочке POSIX?

Сущность этого совпадает с ответом unxnut, но я думаю с помощью sed для чего-то как простой, поскольку разделение расширения является путем излишество:

for f in ./*.py; do mv "$f" "${f%.py}-backup.py"; done

${f%.py} переменный $f, с .py разделенный от конца. Можно также удалить вещи из начала ${f#whatever}. Для рекурсивности (т.е. работающий в текущем каталоге и всех подкаталогах), принимая у Вас есть удар 4 +, можно использовать globstar:

shopt -s globstar
for f in ./**/*.py; do mv "$f" "${f%.py}-backup.py"; done

С другой стороны, можно использовать, переименовывают - существует на самом деле две различных программы, которые используют это имя, и какой, который Вы имеете, будет зависеть от Вашего аромата *, отклоняют. perl-переименуйте (используемый Debian и его производными, такими как Ubuntu и многие другие):

rename 's/\.py$/-rename.py/' ./*.py

Другой переименовывать использовал бы этот синтаксис:

rename .py -backup.py ./*.py

for цикл с mv является более портативным, конечно: первый, нерекурсивный является POSIX и так продолжит работать каждый *, отклоняют где угодно, кроме, возможно, некоторых музейных экспонатов.

4
26.09.2014, 10:18
2 ответа

Оболочка POSIX имеет единый массив: позиционные параметры ($1, $2, ...), коллективно доступные как "$@", и установленные со встроенным набором --. Точнее, на каждый экземпляр функции в текущем стеке вызовов есть один массив, но в любой момент доступен только массив позиционных параметров функции currrent (или скрипта, если он находится вне какой-либо функции). Таким образом, если вы хотите использовать этот массив, но не засорять параметры скрипта, то работайте в функции.

Так как sml уже заметил, ваш конкретный случай использования grep проще решить с помощью опции -F grep, чтобы заставить его читать по одному шаблону на файловую строку. Но вот как можно решить ту же проблему для команды, которая не имеет ничего похожего на grep -F.

set -- -a -b
while IFS= read -r line; do
  set -- -e "$line"
done < "$dictionary"
mycommand "$@" more stuff

Это вызывает mycommand -a -b line1 line2 ... больше вещей.

Если вам необходимо манипулировать несколькими списками имен файлов (или другими строками с произвольным содержимым), вы можете сделать это с помощью eval и очень осторожного цитирования. Получить кавычки сложно. Следующая функция принимает два аргумента: имя переменной и строку; она добавляет к переменной строку в кавычках. Цитируемая форма - это однокавычный литерал, с одинарными кавычками, подходящими для разбора оболочки.

append_to_quoted_list () {
  set -- "$1" "$(printf %s. "$2" | sed "s/'/'\\\\''/")"
  eval "$1=\"\${$1} '${2%?}'\""
}

Вот пример использования для построения двух списков одновременно. Он вызывает $command1 со строками, переданными в качестве аргументов в опциях -e, затем $command2 со строками, переданными в качестве аргументов в опциях --foo=....

list1= list2=
append_to_quoted_list list1 "$command1"
append_to_quoted_list list1 "$command2"
while IFS= read -r line; do
  append_to_quoted_list list1 -e
  append_to_quoted_list list1 "$line"
  append_to_quoted_list list2 "--foo=$line"
done < "$dictionary"
eval "$list1; $list2"
1
27.01.2020, 20:55

С помощью grep Вы не хотите использовать переключатели -f или -F, которые предлагает grep? Из grep man page:

   -F, --fixed-strings
        Interpret PATTERN as a list of fixed strings, separated by 
        newlines, any of which is to be matched.  (-F is specified by 
        POSIX.)

   -f FILE, --file=FILE
        Obtain patterns from FILE, one per line.  The empty file contains 
        zero patterns, and therefore matches nothing.  (-f is specified by
        POSIX.)

Пример

$ grep -F somefile.txt -R .
3
27.01.2020, 20:55

Теги

Похожие вопросы