Как расширение имени файла оболочки разграничивает объекты в (*) список?

Bash отключает историю в неинтерактивных оболочках по умолчанию, но можно включить его.

#!/bin/bash
HISTFILE=~/.bash_history
set -o history
history | tail …

Но при попытке контролировать действие по тому серверу, история оболочки бесполезна (это тривиально к командам выполнения, которые не обнаруживаются в истории). Посмотрите, Как я могу зарегистрировать все запуски процесса в Linux.

Если Вы отлаживаете сценарий, затем окружают историю, не лучший способ получить полезную информацию. Намного лучший инструмент является средством трассировки отладки: поместить set -x около верхней части сценария. Трассировка записана в стандартную погрешность.

5
20.03.2017, 12:18
2 ответа

От удара человека

Расширение РАСШИРЕНИЯ выполняется на командной строке после того, как это было разделено на слова. Существует семь видов выполненного расширения: расширение фигурной скобки, расширение тильды, параметр и переменное расширение, управляет заменой, арифметическим расширением, разделением слова и расширением пути. Порядок расширений: расширение фигурной скобки, расширение тильды, параметр, переменная и арифметическая замена расширения и команды (выполненный слева направо вид), разделение слова и расширение пути.

array=( $names )

Причина это дает Вам 4 записи, состоит в том потому что неупомянутое $names параметр далее подвергается разделению слова на основе внутреннего разделителя полей IFS который является по умолчанию <space><tab><newline>. Если необходимо было заключить в кавычки "$names" для запрещения разделения слова затем Вы только получите один элемент массива со значением f 1 f 2, снова не, что Вы хотите.

array=( * )

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

Если Вы хотите сделать array=( $names ) работайте затем, необходимо будет так или иначе разделить имена файлов непробелом, который также не содержится в именах файлов. Необходимо будет затем установить IFS на этот символ.

$ names=$(echo f* | sed "s/ /#/2")
$ echo $names
f 1#f 2
$ IFS='#' array=( $names )
$ echo ${#array[@]}
2
$ echo ${array[0]}
f 1

Более изящный способ сделать это должно было бы использовать байт NUL \0 как разделитель имени файла, поскольку это, как гарантируют, никогда не будет независимо имени файла. Для выполнения этого, мы должны будем использовать find команда с -print0 флаг, а также read встроенный разграниченный на NUL. Мы хорошо также должны очистить IFS, таким образом, никакое разделение слова на пробелах не выполняется.

#!/bin/bash

unset array

while IFS= read -r -d $'\0' name; do
  array+=( "$name" )
done < <(find . -type f -name "f*" -print0 )

Обновление

Расширение выполняется на командной строке после того, как это было разделено на слова.

Я вижу, как можно было бы быть смущен кавычкой выше только, чтобы иметь его, далее указывают, что разделение слова является 2-м для длительности расширения для появления.

Лучший путь к слову, которые заключают в кавычки, по-моему, был бы:

Расширение выполняется на командной строке после того, как это было разделено на аргументы.

Разделение аргументов на оболочке всегда делается пробелом, и именно те аргументы далее подвергаются расширению. Если Вы хотите иметь пробел в своем аргументе, необходимо или использовать Заключение в кавычки или Выход. IFS не увеличивает разделение аргумента, только разделение слова.

Рассмотрите этот пример:

$ touch f{1,2}; IFS="#"; rm f1#f2
rm: cannot remove `f1#f2': No such file or directory

Заметьте как установка IFS кому: # не изменил то, что оболочка все еще только видела один аргумент f1#f2; который между прочим затем далее подвергается различным расширениям.

Я настоятельно рекомендовал бы Вашу акватинту самостоятельно с BashFAQ, если Вы уже не имеете. В частности, я настоятельно рекомендовал бы, что Вы читаете следующие две дополнительных записи:

  1. Аргументы
  2. Word Splitting
2
27.01.2020, 20:38
  • 1
    я медленно добираюсь там. Я начал читать все man bash (10% до сих пор :). Теперь, об этой проблеме в частности. Я начинаю получать ощущение его, но если мой compehension не является путем прочь, выборка страницы справочника, которую Вы заключили в кавычки, говорит, "Expansion is performed on the command line after it has been split into words..." и затем продолжает, который одно из "расширений" word splitting. Это похоже на противоречие.. таким образом, это поднимает проблему "механизма" снова.. Я только что заметил, что Gilles отправил и упоминает что-то о "словах оболочки".. (но я должен пойти теперь... назад позже), –  Peter.O 12.03.2011, 02:43
  • 2
    @fred.bear см. мой обновленный ответ, это должно поместить для отдыха любого сомнения, которое Вы, возможно, имели относительно "механики" оболочки. –  SiegeX 12.03.2011, 03:35
  • 3
    я уверен ответ, вероятно, явно очевиден и в Вашем ответ и в ответе Gilles, но непока я не могу на самом деле видеть его, я не могу оценить 'лучший' ответ.. Они - и хорошие ответы и имеют меня на правильном пути... Я собираюсь пройти Ваш обновленный ответ теперь... Возможно, я упускаю суть, потому что я думал, что единственная вещь, что "разделение слова" сделало, состояла в том, чтобы удалить дублирующиеся пробелы между кем-либо и всеми "словами", но я начинаю думать, что расширение имени файла создает очень нечеловеческое слово (т.е. слово, которое включает пробелы), иначе как присваивание массива работает? $richard –  Peter.O 12.03.2011, 06:56
  • 4
    Представление слова "аргумент", выигранный спор. Это соответствует моему ходу мыслей развития, таким образом, я, вероятно, понимаю это теперь... (Я просто должен провести в жизнь его)... Действительно однако требовалось два из Вас для прохода через мое толстое весло на этом, и я благодарю вас обоих за информацию в обоих ответах.. Я изучил разные вещи от обоих. –  Peter.O 12.03.2011, 07:18

Команда оболочки (более точно, “простая команда”) состоит из списка слов. Каждое слово может быть произвольной строкой (слово оболочки может содержать пробелы и знаки пунктуации).

Когда Вы работаете echo -n *, оболочка выполняет расширение пути (также названный поколением имени файла или globbing) на *, и замены это списком соответствия именам файлов. Таким образом, после расширения, эта команда состоит из четырех слов: echo, -n, f 1 и f 2. Команда echo выполняется с двумя аргументами, и это печатает свои споры с промежуточным пространством (и никакая новая строка завершения из-за -n опция). Таким образом, вывод f 1 f 2. Осуществление: создайте другой файл, имя которого состоит из двух последовательных пробелов, выполненных echo -n *, и удостоверьтесь, что Вы понимаете вывод.

Когда Вы работаете names=$(echo -n * ), вывод от команды хранится в names переменная. Здесь, та строка эквивалентна names='f 1 f 2'.

Теперь мы добираемся до array=( $names ). Это - присваивание массива, но оно не влияет на расширение в этом случае. С тех пор $names неупомянутое переменное расширение, оно подвергается разделению слова, сопровождаемому расширением пути. Word, разделяющий средства, что значение переменной (который является строкой) разделяется на части в каждой пробельной последовательности (для точных правил, поиска IFS в документации Вашей оболочки). Можно закончить с нулем, одним или несколькими словами; здесь строка разделяется на 4 слова: f, 1, f и 2. Таким образом, массив содержит четыре элемента (каждый слово с одним символом). Осуществление: с тем дополнительным файлом с двумя последовательными пробелами на его имя, каково теперь точное содержание массива?

Затем, Вы попробовали array=( * ). Здесь, существует отдельное слово в массиве согласно обычным расширениям, последним из которых является расширение пути. С тех пор существует два файла соответствия, массив содержит два слова, названия каждого файла: f 1 и f 2.

С точки зрения практики программирования оболочки, какой совет мы можем потянуть из этого анализа? Ну, во-первых, существует обычный принцип программирования оболочки: всегда помещайте двойные кавычки вокруг переменных расширений, если у Вас нет серьезного основания не к. Затем не храните список в строковой переменной. Если Вы хотите сохранить список имен файлов, поместите его непосредственно в массив:

files=(*)
ls -l "${files[@]}"

Дальнейшее осуществление: создайте файл, имя которого является единственной звездочкой (touch '*') и выполненный эти команды снова. Вы понимаете вывод?

В стороне: zsh не выполняет разделение слова или расширение пути на переменных расширениях. Это делает его вполне немного более нормальным к программе в.

5
27.01.2020, 20:38
  • 1
    Было ли что-то в моем ответе, который Вы не нашли достаточным, или действительно ли это было захватом точки? Просто любопытный –  SiegeX 12.03.2011, 03:00
  • 2
    @SiegeX: Кроме бесполезной диверсии с # как разделитель (который не будет работать, если имя файла будет содержать #), Ваш ответ корректен. Но это не является очень дидактическим. В частности, Вы не объясняете, что команда не является строкой, а списком строк, который часто сбивает с толку для окружения новичков. –  Gilles 'SO- stop being evil' 12.03.2011, 03:09
  • 3
    Мы должны будем согласиться не согласиться относительно # пример, потому что я явно использовал его, чтобы быть дидактическим; намного легче визуализировать # чем байт NUL. Я также сделал специальное замечание, что этот символ не должен иметь независимо имени файла и затем продолжил давать более надлежащее решение для байта NUL. С моей точки зрения Ваш ответ составлял 90%, то же и другие 10% будет более соответствующим как комментарий. Но, Вы не можете добраться до 21K для того, чтобы сделать только комментарии так C'est la vie. –  SiegeX 12.03.2011, 03:26
  • 4
    @SiegeX: Если Вы думаете, что мой ответ составляет 90% то же как Ваш, необходимо работать над педагогикой. Мы объясняем те же факты очень по-другому. –  Gilles 'SO- stop being evil' 12.03.2011, 03:30
  • 5
    @fred.bear: Да. Например, попытайтесь разделить то же слово дважды, но изменить значение IFS промежуточный: Вы получите различные разделения. (foo="one two three,four,,five"; echo $foo; IFS=,; echo $foo) –  Gilles 'SO- stop being evil' 13.03.2011, 13:39

Теги

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