В каких случаях количество пробелов имеет значение в скриптах bash (или другой оболочки)

14

Мне сказали, что пробелы важны в bashдругих сценариях оболочки, и я не должен менять существование пробелов, если я не знаю, что я делаю. Под «изменением существования» я имею в виду либо вставку пробела между двумя непробельными символами, либо удаление пробела между двумя непробельными символами, например, изменение var="$val"на var ="$val"или наоборот. Я хочу спросить

Существуют ли случаи, когда использование одного пробела или нескольких последовательных пробелов в сценарии оболочки имеет значение? ,

(Конечно, вставка / удаление пробела в кавычках имеет значение, например, изменение с echo "a b"на echo "a b"или наоборот. Я ищу примеры, отличные от этого тривиального примера.)

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

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

Вейцзюнь Чжоу
источник

Ответы:

19

Вне кавычек оболочка использует пробел (пробелы, табуляции, перевод строки, возврат каретки и т. Д.) В качестве разделителя слов / токенов. Это значит:

  • Вещи, не разделенные пробелами, считаются одним «словом».
  • Вещи, разделенные одним или несколькими пробельными символами, считаются двумя (или более) словами.

Фактическое количество пробелов между каждой «вещью» не имеет значения, если есть хотя бы один.

саз
источник
Спасибо. Я не могу найти контрпример сам. Я просто хочу убедиться.
Вейцзюнь Чжоу
2
Bash также считает, что каналы и вертикальные вкладки являются пробелами.
fpmurphy
правда. Первоначально я написал «... новые строки и т. д.», а затем изменил его, чтобы явно добавить возврат каретки. случайно уронил «и т. д.».
cas
Что если количество пробелов настолько велико, что программа не помещается в память?
Worse_Username
7
@Worse_Username Пробел не должен помещаться в памяти. Я только что создал скрипт на 48 ГБ на машине с 8 ГБ оперативной памяти и 20 ГБ подкачки. Это бежало просто отлично. Потребовалось 3 минуты, чтобы пройти через все эти пробелы, но в итоге он успешно выполнил echoкоманду с таким большим пробелом между командой и аргументом.
kasperd
23

Это, вероятно, обман, но это:

rm foo\ bar         # "delete the file named 'foo bar'"

отличается от этого:

rm foo\  bar        # "delete the files named 'foo ' and 'bar'"

хотя пробелы не в кавычках. ;-)

Более смешно, это:

rm \
    foo          # "delete the file named 'foo'"

отличается от этого:

rm \ 
    foo          # "delete the file named ' ', then run the command 'foo'"

хотя они выглядят одинаково!

ruakh
источник
Несмотря на то, что пробелы не в кавычках, обратная косая черта функционально похожа на форму цитирования, и я бы отнес это к той же категории, что и «тривиальный пример» вопроса. (Хотя это интересно.)
David Z
12

Если мы не будем говорить о космическом характере ( U+0020), но любой символ пробела ( U+0020, \n, \tи т.д.), то один конкретный случай приходит мне на ум: вот-документы.

Этот код (с использованием пробелов):

cat <<- 'EOF'
<space><space>foo
EOF

Распечатает:

  foo

Но этот код (с помощью вкладок):

cat <<- 'EOF'
<tab><tab>foo
EOF

Распечатает:

foo

Это потому что ( как утверждает POSIX ):

Если оператор перенаправления имеет значение <<-, все начальные символы <tab> должны быть удалены из строк ввода и строки, содержащей конечный разделитель.

nxnev
источник
1
Это интересно. Я думал здесь о документах, но не знал <<-оператора. Большое спасибо.
Вейцзюнь Чжоу
здесь документы - это форма цитируемого текста, а не код оболочки. разделение слов оболочки не применяется.
cas
2

Это также оказывает влияние при написании операторов присваивания. Например, если я скажу, FOO=xyzчто он создаст переменную окружения FOOс именем value xyz, но если я разделю равенства с пробелом, он подумает, что я запускаю программу с именем FOOarg =xyz. Так что это имеет значение, когда дело доходит до определенного синтаксиса.

HSchmale
источник
Обычно FOO=xyzсоздает внутреннюю переменную оболочки, но не переменную среды. Вы нуждаетесь set -aили export FOO=xyzдля этого (то есть сделаете это частью среды непроцессорных подпроцессов).
Hauke ​​Laging