Как я могу санировать или выйти из полных путей, возвращенных realpath или readlink?

realpath и readlink возвратите полные пути:

+akiva@X230:~$ realpath ZannaIsAwesome
/home/akiva/ZannaIsAwesome

Путь как этот легок иметь дело с. Однако что-то вроде этого будет иметь некоторые проблемы:

enter image description here

Например:

enter image description here

Таким образом, имя как это должно быть санировано, чтобы смочь подать его к другим командам. Вариант использования мог бы быть чем-то вроде этого:

+a@X230:~/\e[92mM@r|< $hu+'|'|_e|\|\|0rth [`-_-"]$ bacon=$(realpath pullingATerdon)
+a@X230:~$ vim $bacon 

Само собой разумеется, vim $bacon не будет работать как ожидалось.

Что я могу сделать для очистки того полного пути, таким образом, он будет работать с другими командами?

8
задан 14 March 2017 в 12:21

1 ответ

Как сделать это правильно

В первую очередь, всегда заключайте свои переменные в кавычки. То, что Вы пытаетесь сделать, хорошо работает, если Вы заключаете его в кавычки правильно:

$ 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 рассмотренный, что путь двух каталогов, которые попробовали для нахождения лучшего, и отказавший.

Вот почему это перестало работать, но что произошло, более сложно. Строка, которую Вы использовали, является на самом деле шариком оболочки, конкретно диапазон шарика, который соответствует всем файлам в текущем каталоге, имя которого является одним из этих 5 символов `,-, _ или ". Так как у Вас нет таких файлов в Вашем текущем каталоге, шарик ничему не соответствует и, как поведение по умолчанию в ударе, возвраты себя:

$ 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

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


Некоторые полезные ссылки:

  1. Как я могу найти и безопасно обработать имена файлов, содержащие новые строки, пробелы или обоих?: Один из часто задаваемых вопросов на Wiki превосходного Серого CAT.

  2. Последствия безопасности упущения заключить переменную в кавычки в оболочках удара/POSIX: то же сообщение я сослался в начале этого ответа. Большое и очень подробное объяснение всех вещей, которые могли пойти не так, как надо, если Вам не удается заключить Ваши переменные оболочки в кавычки правильно.

  3. Почему мой сценарий оболочки дросселирует на пробеле или других специальных символах?: все Вы когда-либо хотели знать об обработке произвольных имен файлов в оболочке.

  4. Когда двойное заключение в кавычки необходимо?: Больше о кавычках и переменных, и конкретно нескольких случаях, где Вы не должны заключать им в кавычки

11
ответ дан 23 November 2019 в 05:35

Другие вопросы по тегам:

Похожие вопросы: