Когда вы находитесь в командном режиме в vi
(фактический редактор или режим Bash), нажатие цифр вводит аргумент (отсюда «arg»), который обычно используется для установки количества повторений. для выполнения следующей команды. Чтобы этого избежать, вы должны перейти в режим ввода (например, нажав i ) перед тем, как нажимать цифры.
Демонстрация:
Если вы не находитесь в режиме vi, вы можете войти в него, используя:
set -o vi
(Вы можете выйти из режима vi, войдя в режим emacs: set -o emacs
)
Теперь, в режиме ввода vi введите такую команду:
echo abcdefghijk4
Вы заметите, что в конце вы получите цифру «4», как показано выше.
Теперь нажмите Esc . Курсор переместится на один символ влево, и вы перейдете в командный режим.
Нажмите цифру, скажем «3». Теперь вы увидите это:
(arg: 3) echo abcdefghijk4
Теперь нажмите заглавную X. Вы должны увидеть:
echo abcdefgh4
Три символа («ijk») были удалены, потому что вы указали Readline (редактор ввода командной строки Bash) «стирать» 3 символа .
Теперь нажмите i и любую цифру. Цифра была вставлена в командную строку в том месте, где находился курсор.
some_command --flag "$(printf '%s' foo\
bar\
quux)" arg2
подойдет, хотя это не самый читаемый текст. Это передает «foo», «bar» и «quux» в качестве аргументов команде printf
с %s
в качестве строки формата. Когда символов формата задано меньше, чем аргументов, строка формата повторяется по мере необходимости, что делает ее эквивалентной %s%s%s
, или все три строки печатаются одна за другой без пробелов между ними. Наконец, вывод команды printf
, «foobarquux», подставляется в качестве аргумента для some_command
.
Использование вспомогательной функции:
concat () (
IFS=
printf '%s' "$*"
)
printf '"%s"\n' "$(concat "foo" \
"bar" \
"baz" )"
Это выведет
"foobarbaz"
Или, сначала поместив строковые биты аргумента в массив, а затем отдельно создав фактический аргумент (, предполагается использование оболочки с массивами):
concat () (
IFS=
printf '%s' "$*"
)
args=(
"foo"
"bar"
"baz"
)
concat_args=$( concat "${args[@]}" )
printf '"%s"\n' "$concat_args"
То же, что и выше, но с оболочкой POSIX.:
concat () (
IFS=
printf '%s' "$*"
)
set -- \
"foo" \
"bar" \
"baz"
concat_args=$( concat "$@" )
printf '"%s"\n' "$concat_args"
Обратите внимание, что тело функции concat
выполняется в своей собственной подоболочке (, что и (...)
делает ), что означает, что изменение в IFS
является локальным для функции.
Обоснование использования "$*"
вместо "$@"
в функции чисто для эстетики. "$*"
расширится до одиночной строки, которая printf
будет напечатана. Фактическая конкатенация в этом случае выполняется расширением оболочки $*
без разделителя (пустым$IFS
). Вместо этого использование "$@"
расширило бы количество отдельных строк, к которым printf
неоднократно применяла бы свою строку формата. Конкатенация в этом случае будет побочным эффектом использования конкретной строки формата с printf
.
Или та же идея (создание фактической строки аргумента отдельно ), но без этой вспомогательной функции,
arg=\
"foo"\
"bar"\
"baz"
printf '"%s"\n' "$arg"
printf '"%s"\n'
выше во всех случаях будет заменен вашим some_command --flag
.