Странное поведение argv при передаче строки, содержащей "!!!!"

Я написал небольшую программу, которая принимает некоторые входные параметры из *argv[] и печатает их. Почти во всех случаях использования мой код работает отлично. Проблема возникает только тогда, когда я использую более одного восклицательного знака в конце строки, которую я хочу передать в качестве аргумента...

Это работает:

./program -m "Hello, world!"

Это не работает:

./program -m "Hello, world!!!!"

^^ Если я это сделаю, вывод программы будет либо в две строки, либо в предыдущую команду. /program.

Однако, что я абсолютно не понимаю: следующее, как ни странно, работает:

./program -m 'Hello, world!!!!'

^^ Выход точно...

Hello, world!!!!

... так же, как хотелось бы.

Итак, мои вопросы:

  • Почему это странное поведение возникает при использовании нескольких восклицательных знаков в строке?
  • Насколько я знаю, в C вы используете "" для строк и '' для отдельных символов". Так почему я получаю желаемый результат при использовании '', но не при использовании "" как должен (в моем понимании)?
  • Есть ли ошибка в моем коде или что мне нужно изменить, чтобы иметь возможность вводить любую строку (независимо от того, что, сколько и сколько знаков препинания используется) и получить именно эту строку?

Соответствующие разделы моего кода:

// this is a simplified example that, in essence, does the same 
// as my (significantly longer) code
int main(int argc, char* argv[]) {
    char *msg = (char *)calloc(1024, sizeof(char));

    printf("%s", strcat(msg, argv[2])); // argv[1] is "-m"

    free(msg);
}

Я уже попробовал сначала скопировать содержимое argv[2] в буфере char* и добавить к нему '\0', что ничего не изменило.

Ответ 1

Это не относится к вашему коду, а к оболочке, которая его запускает.

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

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

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

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

Ответ 2

Оболочка расширяет строки с двойными кавычками. И если вы прочитаете страницу руководства Bash (предполагая, что вы используете Bash, которая по умолчанию используется для большинства дистрибутивов Linux), то если вы посмотрите раздел "Расширение истории", вы увидите это !! средства

Обратитесь к предыдущей команде.

Так что !!!! в вашей двойной кавычки строка будет дважды расширяться до предыдущей команды.

Такое расширение не выполняется для однокасканных строк.

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

Ответ 3

В дополнение к предоставленным ответам вы должны помнить, что эхо - ваш друг оболочки. Если вы префикс своей команды с помощью "echo", вы увидите, какая оболочка действительно отправляет ваш скрипт.

echo ./program -m "Hello, world!!!!"

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