Bash globbing и передача параметров

Если Ваша поддержка приложений это, можно попробовать передающий порт 0 к приложению. Если Ваше приложение передаст это ядру, то порт будет динамично выделен во время запроса и, как гарантируют, не будет использоваться (выделение перестанет работать, если все порты уже будут использоваться).

Иначе можно сделать это вручную. Сценарий в Вашем ответе имеет состояние состязания, единственный способ избежать, чтобы это атомарно проверило, открыто ли это путем попытки открыть его. Если порт используется, программа должна выйти с отказом открыть порт.

Например, скажите, что Вы пытаетесь послушать с GNU netcat.

#!/bin/bash
read lower_port upper_port < /proc/sys/net/ipv4/ip_local_port_range
while :; do
    for (( port = lower_port ; port <= upper_port ; port++ )); do
        nc -l -p "$port" 2>/dev/null && break 2
    done
done
8
18.11.2013, 14:03
2 ответа

Вы присваиваетесь files как скалярная переменная вместо переменной типа массив.

В

 files=$HOME/print/*.pdf

Вы присваиваете некоторую строку как /home/highsciguy/print/*.pdf к $files скаляр (иначе строка) переменная.

Использование:

files=(~/print/*.pdf)

или

files=("$HOME"/print/*.pdf)

вместо этого. Оболочка развернет это globbing шаблон в список путей к файлам и присвоит каждого из них к элементам $files массив.

Расширение шарика сделано во время присвоения.

Вы не должны использовать нестандартные sh функции, и Вы могли использовать свою систему sh вместо bash здесь путем записи этого:

#!/bin/sh -

[ "$#" -gt 0 ] || set -- ~/print/*.pdf

for file do
  ls -d -- "$file"
done

set должен присвоиться "$@" массив позиционных параметров.

Другой подход, возможно, был должен сохранить globbing шаблон в скалярной переменной:

files=$HOME/print/*.pdf

И имейте оболочку, разворачивают шарик в то время $files переменная расширена.

IFS= # disable word splitting
for file in $files; do ...

Здесь, потому что $files не заключается в кавычки (который Вы не должны обычно делать), его расширение подвергается разделению слова (который мы отключили здесь), и globbing/filename поколение.

Так *.pdf будет расширен до списка соответствия файлам. Однако, если $HOME содержавшие подстановочные символы, они могли быть расширены также, который является, почему все еще предпочтительно использовать переменную типа массив.

10
27.01.2020, 20:10

Вы, возможно, видели вещи как files=$* и files=~/print/*.pdf в более старых оболочках без массивов, и затем ls $files.

Подстановка переменных, которая не является в двойных кавычках, интерпретирует значение переменной как разделенный от пробела список подстановочных шаблонов оболочки, которые заменяются путем соответствия именам файлов, если существует кто-либо. Например, после files=~/print/*.pdf, ls $files расширяется до чего-то как ls с аргументами /home/highsciguy/print/bar.pdf, /home/highsciguy/print/foo.pdf, и т.д. В случае files=$*, это присвоение конкатенирует, аргументы передали сценарию с промежуточными пробелами, и ls $files разделяет их, отступают.

Все это ломается, если у Вас есть имена файлов, содержащие пробел или globbing символы, который является, почему Вы не должны делать вещей этот путь. Используйте массивы вместо этого.

files=("$@")
if ((${#files[@]} == 0)); then
  files=("$HOME"/print/*.pdf)
fi

Отметьте это

  • Все присваивание массива требует круглых скобок вокруг значений массива: var=(…).
  • Чтобы протестировать, пуст ли массив, проверьте его длину. "$files" пусто когда files массив, чей элемент индекса 0 сброшен или пустая строка. Также [ "X$foo" = "X" ] устаревший путь состоит в том, чтобы протестировать ли $foo пусто: вся современная реализация оболочек [ -n "$foo" ] правильно. В ударе можно использовать [[ -n $foo ]].

В оболочках, которые не поддерживают массивы, существует на самом деле один массив: позиционные параметры к оболочке или текущей функции. Здесь, Вам действительно не нужно files массив, на самом деле было бы легче использовать позиционные параметры.

#!/bin/sh
if [ "$#" -eq 0 ]; then
  set -- ~/print/*.pdf
fi
for file do …
4
27.01.2020, 20:10

Теги

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