Как сделать это правильно
Прежде всего, всегда указывайте свои переменные . То, что вы пытаетесь сделать, работает нормально, если вы цитируете это правильно:
$ pwd
/home/terdon/foo/\e[92mM@r|< +'|'|_e|\|\|0rth [`-_-"]
$ ls
pullingATerdon
Я сохранил странное имя файла, которое вы выбрали ( хотя я понятия не имею, почему вы выбрали его ) для согласованности.
Теперь давайте назначим путь pullingATerdon
к переменной, а затем попробуем открыть файл:
$ bacon="$(realpath pullingATerdon)"
$ echo "$bacon"
/home/terdon/foo/\e[92mM@r|< +'|'|_e|\|\|0rth [`-_-"]/pullingATerdon
$ ls $bacon
ls: cannot access '+'\''|'\''|_e|\|\|0rth': No such file or directory
ls: cannot access '[`-_-"]/pullingATerdon': No such file or directory
'/home/terdon/foo/\e[92mM@r|<':
Это терпит неудачу, как и ожидалось. Но если мы сейчас процитируем это правильно:
$ ls -l "$bacon"
-rw-r--r-- 1 terdon terdon 0 Mar 14 23:15 '/home/terdon/foo/\e[92mM@r|< +'\''|'\''|_e|\|\|0rth [`-_-"]/pullingATerdon'
Работает как положено. И да, вы также можете открыть путь в (правильном) редакторе: все emacs "$bacon"
будет работать нормально. ОК, так будет vim
и все остальное. Ваш выбор редактора, хотя и неудачный, не имеет значения.
Почему твой провал
Быстрый способ отследить то, что на самом деле произошло в вашем случае, - это использовать set -x
(выключите его снова с помощью set +x
), что заставляет оболочку печатать каждую команду, которую она выполнит перед выполнением. включите сообщения отладки оболочки с помощью set -x
:
$ set -x
$ /bin/ls $bacon
+ ls '/home/terdon/foo/\e[92mM@r|<' '+'\''|'\''|_e|\|\|0rth' '[`-_-"]/pullingATerdon'
ls: cannot access '+'\''|'\''|_e|\|\|0rth': No such file or directory
ls: cannot access '[`-_-"]/pullingATerdon': No such file or directory
'/home/terdon/foo/\e[92mM@r|<':
Это говорит о том , что ls
была запущена с тремя отдельными аргументами: '/home/terdon/foo/\e[92mM@r|<'
, '+'\''|'\''|_e|\|\|0rth'
и '[`-_-"]/pullingATerdon'
. Это происходит потому, что оболочка выполняет разбиение слов и расширение глобуса для строк без кавычек. В этом случае проблема заключается в разделении слов, поскольку оболочка видит пробелы в пути и считывает каждую разделенную пробелами строку как отдельный аргумент.
mkdir
Пример немного отличается , но это потому , что вы показываете нам сообщение об ошибке от второго вызова команды. Я полагаю, вы попробовали это один раз, а затем запустили во второй раз, чтобы получить ответ на свой вопрос. Первый раз, когда вы запустили его, это выглядело бы так:
$ mkdir $(realpath pullingATerdon)
++ realpath pullingATerdon
+ mkdir '/home/terdon/foo/\e[92mM@r|<' '+'\''|'\''|_e|\|\|0rth' '[`-_-"]/pullingATerdon'
mkdir: cannot create directory ‘[`-_-"]/pullingATerdon’: No such file or directory
Опять же, это попытается создать три каталога, а не один, из-за разделения слов. Во-первых, он создал (успешно) каталог /home/terdon/foo/\e[92mM@r|<
:
$ ls -l /home/terdon/foo/
total 8
drwxr-xr-x 2 terdon terdon 4096 Mar 15 00:20 '\e[92mM@r|<'
drwxr-xr-x 3 terdon terdon 4096 Mar 15 00:20 '\e[92mM@r|< +'\''|'\''|_e|\|\|0rth [`-_-"]'
Затем он также успешно создал каталог с именем +'|'|_e|\|\|0rth
в вашем текущем каталоге:
$ ls -l
total 4
drwxr-xr-x 2 terdon terdon 4096 Mar 15 00:37 '+'\''|'\''|_e|\|\|0rth'
-rw-r--r-- 1 terdon terdon 0 Mar 15 00:36 pullingATerdon
А затем он попытался создать каталог [`-_-"]/pullingATerdon
. Это не удалось, потому что mkdir
по умолчанию не создаются подкаталоги (это возможно, если вы запускаете его с помощью -p
):
$ mkdir baz/bar
mkdir: cannot create directory ‘baz/bar’: No such file or directory
Поскольку ваша строка без кавычек содержала a /
, mkdir
считала, что путь из двух каталогов, пыталась найти верхнюю и потерпела неудачу.
Вот почему это не удалось, но то, что произошло, сложнее. Строка, используемая на самом деле оболочка Глоба, конкретно диапазон Glob , который соответствует всем файлам в текущем каталоге, имя которого один из 5 символов `
, -
, _
или "
. Поскольку у вас нет таких файлов в текущем каталоге, глобус ничего не соответствует и, как это принято в bash по умолчанию, возвращает себя:
$ echo "[\`-_-\"]/pullingATerdon" ## some escaping is needed here
+ echo '[`-_-"]/pullingATerdon' ## but it echoes the right thing
[`-_-"]/pullingATerdon ## and matches nothing, so returns itself.
Чтобы уточнить, вот что происходит, если вы даете глобус, который действительно соответствует чему-то:
$ echo [p]* ## any filename starting with a p
pullingATerdon
$ echo "[p]*" ## the string "[p]*"
[p]*
Без кавычек [p*]
расширяется до списка совпадающих имен файлов (в данном случае только одно), и это то, что передается echo
. Еще одна причина, почему вы должны цитировать все вещи.
Наконец, вы видите фактическую ошибку со второго раза, когда вы запустили команду, и она завершается с ошибкой на первом шаге при попытке создания /home/terdon/foo/\e[92mM@r|<
, потому что предыдущий вызов уже создал этот каталог.
В общем, всякий раз, когда вы работаете с произвольными именами файлов, всегда используйте оболочки оболочки. Вещи как это:
for file in *; do command "$file"; done
Это будет работать для любого имени файла. Неважно, что это содержит. В нашем примере выше вы могли бы сделать:
emacs /home/terdon/*92mM*/pullingATerdon
Подойдет любой глобус, который однозначно идентифицирует целевой файл. Таким образом, вам не нужно беспокоиться о специальных символах, и вы можете просто позволить оболочке обрабатывать их.
Несколько полезных ссылок:
Как я могу найти и безопасно обрабатывать имена файлов, содержащие переводы строк, пробелы или оба? : Один из часто задаваемых вопросов о превосходном Wiki Grey Cat.
Последствия для безопасности: забыть процитировать переменную в оболочках bash / POSIX : тот же пост, на который я ссылался в начале этого ответа. Отличное и очень подробное объяснение всех вещей, которые могут пойти не так, если вам не удастся правильно процитировать ваши переменные оболочки.
Почему мой сценарий оболочки задыхается от пробелов или других специальных символов? : все, что вы когда-либо хотели знать об обработке произвольных имен файлов в оболочке.
Когда необходимо двойное цитирование? : Подробнее о кавычках и переменных и, в частности, о нескольких случаях, когда вам не нужно их заключать в кавычки
vim "$bacon"