Як я можу оздоровити або уникнути абсолютних шляхів, повернених realpath чи readlink?


9

realpathі readlinkповернути абсолютні шляхи:

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

Такий шлях легко подолати. Однак у подібного виникнуть деякі проблеми:

введіть тут опис зображення

Наприклад:

введіть тут опис зображення

Таким чином, таке ім'я потрібно знезаразити, щоб мати можливість подавати його іншим командам. Шкаф може бути приблизно таким:

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

Потрібно сказати, що vim $baconне буде працювати, як очікувалося.

Що я можу зробити, щоб переосмислити цей абсолютний шлях, щоб він працював з іншими командами?


3
Завжди vim "$bacon"
цитуйте

@steeldriver Чому це?
Аківа

3
Тому що якщо ви цього не зробите, ви потрапляєте у подібні ситуації :)
terdon

Відповіді:


12

Як це зробити правильно

Перш за все, завжди цитуйте свої змінні . Те, що ви намагаєтеся зробити, працює добре, якщо ви цитуєте це правильно:

$ 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

Буде робити будь-який глобус, який однозначно ідентифікує цільовий файл. Таким чином, вам не потрібно турбуватися про спеціальні символи, і ви можете просто дозволити оболонці обробляти їх.


Деякі корисні посилання:

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

  2. Вплив на безпеку забуття процитувати змінну в оболонках bash / POSIX : той самий пост, на який я посилався на початку цієї відповіді. Чудове і дуже детальне пояснення всіх речей, які можуть піти не так, якщо ви не зможете цитувати змінні оболонки правильно.

  3. Чому мій сценарій оболонки задавлюється пробілом або іншими спеціальними символами? : все, що ви коли-небудь хотіли знати про обробку довільних імен файлів у оболонці.

  4. Коли потрібно подвійне цитування? : Більше про лапки та змінні, а саме про декілька випадків, коли вам не потрібно цитувати їх

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.