1

Работая на OS X 10.11.1, я выполняю следующую последовательность команд (одну за другой) в консоли:

FILE="a b c.tiff"  # file in the current folder
VAR=$(mdls -name kMDItemContentCreationDate $FILE) # storing the creation time string  
TS=$(echo ${VAR[2]}; echo ${VAR[3]}  # saving the date and time only
echo $TS  

и расширение работает прекрасно. Вывод показывает:

2016-01-16 15:34:29

Однако, когда я сохраняю их в скрипте и запускаю, кажется, что во время оценки что-то другое.

Отладка (с помощью bash -x) дает:

FILE='a b c.tiff'
mdls -name kMDItemContentCreationDate a b c.tiff
VAR='a: could not find a.'
echo
echo
TS=
echo

Я вижу, что расширение ведет себя по-другому.

Меня беспокоит, почему возникает такая разница и как мне исправить свой сценарий.Спасибо.

1 ответ1

2

Я уверен, что вы не выполняли эти точные команды в консоли, иначе вы бы получили тот же результат. Здесь есть две серьезные проблемы и несколько плохих сценариев. Сначала серьезные проблемы:

  • Когда вы ссылаетесь на переменную (например, $FILE) без двойных кавычек вокруг нее, оболочка разделяет ее на "слова", а затем расширяет любые символы подстановки, прежде чем передать ее команде. В этом случае это означает, что a b c.tiff будет разделен на "a", "b" и «c.tiff». Вот почему вы получаете "не удалось найти". ошибка.

    Решение: вы должны помещать ссылки на переменные в двойные кавычки, если только вы не хотите разделять слова и подстановочные знаки. (Есть некоторые случаи, когда отбрасывать двойные кавычки безопасно, но отслеживать их - больше проблем, чем стоит. Просто привыкните использовать двойные кавычки.)

  • Когда вы используете присваивание типа VAR=$(somecommand) , оно присваивает переменную в виде простой строки, а не массива. Чтобы сохранить его в виде массива, используйте скобки справа, как в VAR=( $(somecommand) ) . Обратите внимание, что, поскольку $(somecommand) не находится в двойных кавычках, он будет разбит на слова и расширен с подстановочными знаками, но в этом случае мы хотим, чтобы слово было разделено (поэтому каждое "слово" хранится в отдельном элементе массива ), и формат вывода достаточно предсказуем, чтобы расширение с использованием подстановочных знаков не сделало бы ничего странного, чтобы нас напортачить. Так что это один из редких случаев, когда можно не использовать двойные кавычки.

С этими двумя фиксированными, вторая строка становится:

VAR=( $(mdls -name kMDItemContentCreationDate "$FILE") )

Теперь, для некоторых вещей, которые являются плохими привычками сценариев, которые фактически не вызывают проблемы здесь:

  • В присваивании TS=$(echo ${VAR[2]}; echo ${VAR[3]}) (примечание: я добавил пропущенную закрывающую скобку), команды подстановки команд и команды echo ничего полезного не делают. Для этого нужно взять значения элементов массива, разбить их по словам и подстановить их по шаблону (что здесь ничего не делает), передать их в качестве параметров командам echo , взять выходные данные этих команд и собрать их в переменную. Это большая работа, чтобы соединить две строки. Просто используйте `TS =" $ {VAR [2]} $ {VAR [3]} ".

    Кстати, он также делает что-то немного странное: он склеивает строки вместе с новой строкой между ними. Когда вы печатаете его с помощью echo $TS , он (снова) получает разбиение по словам, поэтому каждая строка обрабатывается как отдельный аргумент echo , который вставляет пробелы между аргументами. Чистый результат: команда echo эффективно преобразует новую строку в пробел. Во-первых, было бы намного чётче сделать его пробелом, а затем использовать его в двойных кавычках, когда вы его используете, чтобы ваш сценарий не зависел от двух странных вещей, которые оказываются взаимно уничтожающими друг друга.

  • Наконец, использование переменных с заглавными буквами не очень безопасно. Существует несколько переменных all-caps, которые имеют особое значение для оболочки (и некоторых команд), и если вы случайно используете одну из них, вы можете получить странные результаты. Классическим примером является присвоение чего-либо переменной PATH, после чего все команды внезапно становятся неопознанными. Трудно отследить все магические переменные, поэтому просто используйте строчные переменные для своих вещей, и вы будете в безопасности.

Со всем этим вымыто вот то, что я получаю для сценария:

file="a b c.tiff"  # file in the current folder
var=( $(mdls -name kMDItemContentCreationDate "$file") ) # storing the creation time string as an array
ts="${var[2]} ${var[3]}"  # saving the date and time only
echo "$ts"

Последнее замечание: если вы сомневаетесь, запустите ваш скрипт через shellcheck.net - он укажет на многие стандартные ошибки новичка и сэкономит вам много времени!

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .