Это происходит для символа t и корня значения. Довольно недоумение
$ echo [s]
[s]
$ echo [t]
t
$ echo [ t ]
[ t ]
$ echo [root]
t
Это происходит для символа t и корня значения. Довольно недоумение
$ echo [s]
[s]
$ echo [t]
t
$ echo [ t ]
[ t ]
$ echo [root]
t
Не являясь оболочкой habitué (и не желая становиться), я нашел удивительным, как расширение имени файла должно вести себя, когда совпадений не найдено. Я сообщу Bash ссылку
Bash сканирует каждое слово для символов
*,?и[. Если один из эти символы появляются, тогда слово рассматривается как шаблон, и заменяется алфавитно отсортированным списком имен файлов, соответствующих шаблон. Если совпадающие имена файлов не найдены:
- если опция оболочки
nullglobотключена, слово остается неизменным- Если установлена опция оболочки
nullglob, слово удаляется- Если установлена опция оболочки
failglob, выводится сообщение об ошибке и команда не выполняется
Хорошая новость заключается в том, что эта вещь настраивается. Плохой - это script, который может потерпеть неудачу несколькими способами, которых вы не ожидаете - по крайней мере, я этого не сделал, и мне потребовалось некоторое время, чтобы понять, почему echo ведет себя так, как вы это делали, просто чтобы найти, что это из-за комбинации странных имен файлов (кто когда-либо хочет назвать файл t?), скрытая конфигурация (nullglob отключена, опция по умолчанию, но все еще скрыта) и безобидная команда.
Я сказал безвредный, потому что это то, что вы получаете, например, когда цель ls (сбой, потому что файл не найден):
[email protected]:~$ mkdir test
[email protected]:~$ cd test
[email protected]:~/test$ touch t
[email protected]:~/test$ ls [t]
t
[email protected]:~/test$ ls [v]
ls: cannot access [v]: No such file or directory
[] обозначает класс символов, и у вас есть файл с именем t в вашем текущем каталоге.
Далее следует пояснить следующее:
$ ls
$ echo [t]
[t]
$ touch t
$ echo [t]
t
$ echo [root]
t
$ touch r
$ echo [root]
r t
Если вы хотите повторить что-то в [], отпустите [:
echo \[$var]
Обратите внимание на разницу:
$ echo \[root]
[root]
или, как Гленн Джекман указывает,
$ echo '[root]'
[root]
$ echo "[root]"
[root]
Shell Command Language говорит, что следующие символы являются особыми для оболочки в зависимости от контекста:
* ? [ # ~ = %
Кроме того, следующие символы должны быть указаны, если они должны представлять себя:
| & ; < > ( ) $ ` \ " ' <space> <tab> <newline>
Вы также можете использовать printf, чтобы определить, какие символы в заданном входе должны быть экранированы, если вы не указываете аргументы. Для вашего примера, т.е. [s]:
$ printf "%q" "[s]"
\[s\]
Другой пример:
$ printf "%q" "[0-9]|[a-z]|.*?$|1<2>3|(foo)"
\[0-9\]\|\[a-z\]\|.\*\?\$\|1\<2\>3\|\(foo\)
[] обозначает класс символов. Проще говоря, класс символов - это способ обозначить набор символов таким образом, чтобы соответствовать одному символу. [A-Z] - очень распространенный пример - он соответствует всем алфавитам от A до Z.
Ниже приведены результаты команд в новом каталоге:
$ echo [s]
[s]
$ echo [t]
[t]
$ echo [ t ]
[ t ]
$ echo [root]
[root]
Как вы можете видеть, echo отображает их как есть. Зачем? Прочтите следующий раздел.
Каждый раз, когда вы вводите команду в терминал и нажимаете клавишу ENTER, bash выполняет много операций внутри, прежде чем распечатывать результаты в оболочку. Простейшим примером является расширение *:
$ echo *
evil_plans.txt dir1 dir2
Вместо вывода литерала * в качестве вывода он распечатал содержимое каталога. Почему это случилось? Потому что * имеет особое значение - это подстановочный знак, который может соответствовать любому символу имени файла. Важно отметить, что команда echo вообще не видит * - только расширенный результат.
Существуют разные виды расширений:
... и, вероятно, больше. В этом случае расширение имени файла является соответствующим типом расширения.
Когда вы вводите команду echo и нажимаете ENTER, bash обрабатывает команду и разбивает ее на слова. Как только это будет сделано, он сканирует слова для следующих символов: ?, * и [. Все это метасимволы и имеют особое значение. Если bash обнаруживает появление любого из этих символов, он рассматривает поставляемое слово как шаблон.
Например, рассмотрим следующий случай:
$ touch foobar foobak fooqux barbar boofar
$ echo foo*
foobar foobak fooqux
Как вы можете видеть, * расширил и перечислил совпадающие имена файлов. (В этом случае те, которые начинаются с foo.)
Теперь попробуйте еще один пример:
$ touch gray.txt grey.txt
$ echo gr?y.txt
gray.txt grey.txt
? соответствует одному символу. Больше ничего. В этом случае gray.txt и grey.txt совпадали с шаблоном, поэтому оба были напечатаны.
Другой пример:
$ touch hello hullo hallo
$ echo h[aeu]llo
hallo hello hullo
Что здесь произошло? Как вам известно, [aeu] - это класс символов. Класс символов соответствует именно одному из символов в нем; он никогда не соответствует более чем одному символу. В этом случае символы в классе символов могут корректно соответствовать именам файлов, поэтому результаты были распечатаны.
Если совпадающие имена файлов не найдены, слово остается неизменным.
$ echo [s]
[s] является символьным классом и соответствует только одному символу - литералу s. Но совпадающих файлов не найдено, поэтому оно было возвращено как есть.
$ echo [t]
[t] также является символьным классом. Он соответствует одному символу. В вашем каталоге был файл с именем t, то есть был матч. Таким образом, оно вернуло имя найденного имени файла.
$ echo [root]
[root] соответствует следующим символам: r, o, t. Как вы, наверное, догадались, o, встречающийся дважды в классе символов, здесь не имеет значения. Класс символов может соответствовать только одному символу. Итак, echo [root] попытается найти имена файлов, которые имеют соответствующий символ. Поскольку в вашем каталоге существует файл с именем t, он указан в списке.
Всегда используйте цитаты и экранирование, если это необходимо. Они дают вам общий контроль над результатами синтаксического анализа, расширения и расширения.
Чтобы дополнить полезный ответ devnull:
Использование строки без кавычек в bash (в большинстве случаев) заставляет ее интерпретироваться как шаблон (выражение подстановочного выражения, свободно говорящее, отдаленный, примитивный родственник регулярного выражения).
В вашем случае шаблон сопоставляется с именами файлов и подпапок в текущей рабочей папке, поскольку @devnull демонстрирует: [root] означает: соответствие любому файлу, имя которого состоит всего из 1 символ r или o (с указанием o дважды является избыточным) или t.
Это сопоставление шаблона с именами файлов называется расширением имени пути.
Обратите внимание, что также относится к ссылкам без кавычек, поэтому следующее даст тот же результат:
s='[t]' # Assign string _literal_ (since quoted) to variable.
echo $s # Content of $s, since unquoted, is now subject to pathname expansion.
Чтобы обрабатывать строку (выборочно) буквально, вы должны использовать цитирование.
В bash есть три способа цитирования строк:
\ - укажите отдельные символы, которые имеют особое значение (так называемые метасимволы):
echo \[t\]
Это гарантирует, что эти другие специальные символы рассматриваются как литералы.
Вставьте строку в одинарные кавычки ('...'):
echo '[t]'
Это защищает строку от любых расширений (интерпретации) оболочкой.
Предостережение: вы не можете включить сам ' в строку с одной кавычкой (даже с экранированием).
Вставьте строку в двойные кавычки ("..."):
echo "[t]"
Это защищает строку от некоторых расширений оболочкой, выборочно разрешая другим.
В данном случае '[t]' и "[t]" ведут себя одинаково.
Однако использование " позволяет ссылаться на переменные (расширение параметров), выполнять подстановки команд и выполнять вычисления (арифметическое расширение)
внутри строки, например:
echo "Home, sweet $HOME." # reference to variable $HOME; parameter expansion
echo "Today date and the current time are: $(date)" # command substitution
echo "Let put $(( 2 + 2 )) together." # arithmetic expansion
Для списка всех расширений, выполняемых bash, найдите раздел EXPANSION в man bash или посетите https://www.gnu.org/software/bash/manual/html_node/Shell-Expansions.html.