Правильный синтаксис и использование команды `cat`? - PullRequest
0 голосов
/ 07 января 2019

(Этот вопрос является продолжением этого комментария, в ответе о git hooks)

Я слишком неквалифицирован в bash (пока), чтобы полностью понять замечание и то, как действовать соответственно. В частности, мне посоветовали не использовать команду bash cat следующим образом:

echo "$current_branch" $(cat "$1") > "$1"

потому что порядок операций зависит от конкретной оболочки и может привести к уничтожению содержимого переданного аргумента, поэтому само сообщение о коммите, если я правильно понял?

Также, как «сохранить содержимое на отдельном шаге»?

Имеет ли смысл следующее:

tmp = "$1"
echo "$current_branch" $(cat $tmp) > "$1"

Ответы [ 3 ]

0 голосов
/ 07 января 2019

Предложенный вопрос не о перезаписи переменных или аргументов, а о том, что как чтение, так и запись в файл одновременно, как правило, плохая идея.

Например, эта команда может выглядеть так, как будто она просто записывает файл в себя, но вместо этого она обрезает его:

cat myfile > myfile   # Truncates the file to size 0

Однако, это не проблема в вашей конкретной команде. Он гарантированно работает в POSIX-совместимой оболочке, поскольку порядок операций указывает , что перенаправления произойдут после расширений:

  1. Слова, которые не являются переменными присваиваниями или перенаправлениями, должны быть расширены. Если какие-либо поля остаются после их расширения, первое поле считается именем команды, а остальные поля являются аргументами команды.

  2. Перенаправления должны выполняться, как описано в разделе Перенаправление.

Двойной - однако , он все еще немного хрупок в том смысле, что казалось бы безобидные модификации могут вызвать проблему, например, если вы хотите запустить sed для результата. Поскольку перенаправление (> "$1") и подстановка команд $(cat "$1") теперь находятся в отдельных командах, определение POSIX больше не спасает вас:

# Command may now randomly result in the original message being deleted
echo "$current_branch $(cat "$1")" | sed -e 's/(c)/©/g' > "$1"

Аналогично, если вы преобразуете его в функцию, он также внезапно перестанет работать:

# Command will now always delete the original message
modify_message() {
  echo "$current_branch $(cat "$1")"
}
modify_message "$1" > "$1"

Вы можете избежать этого, записав во временный файл, а затем заменить свой оригинал.

tmp=$(mktemp) || exit
echo "$current_branch $(cat "$1")" > "$tmp"
mv "$tmp" "$1"
0 голосов
/ 07 января 2019

Команда здесь будет намного лучше, чем подстановка команд. Обратите внимание на сходство с ответом Джено Чена.

{
  echo "$current_branch"
  cat "$1"
} > tmp && mv tmp "$1"
0 голосов
/ 07 января 2019

На мой взгляд, лучше сохранить в другой файл.

Вы можете попробовать что-то вроде

echo "$current_branch" > tmp
cat "$1" >> tmp # merge these into 
# echo "$current_branch" $(cat "$1") > tmp
# may both OK
mv tmp "$1"

Однако я не уверен, правильно ли я понимаю, или есть более лучшие решения.

Это то, что я считал основой вопроса. Трудно определить «приоритет» блока $() и >. Если > выполняется «раньше», то echo "$current_branch" перепишет файл «$ 1», а удалит исходное содержимое «$ 1», что является катастрофой. Если $() выполняется «раньше», то все работает как положено. Однако существует риск, и мы должны его избегать.

...