Как заставить "cd ..." объединить две директории?

429
Jimmy Huch

Итак, в настоящее время на MacOS я настроил псевдонимы, как это ...

alias ...='cd ../..' alias ....='cd ../../..' 

Это позволяет мне перейти на несколько каталогов, набрав ...в моем терминале. Тем не менее, в моей предыдущей настройке, у меня было так, чтобы ввод cd ...был в нескольких каталогах. cdВначале меня научили писать ... как изменить псевдонимы, чтобы они работали так, как я хочу?

1

2 ответа на вопрос

1
Hartmut Braun

С помощью https://stackoverflow.com/questions/941338/how-to-pass-command-line-arguments-to-a-shell-alias ваша проблема может быть решена так:

alias cd='function _cd(){ cd $; }; _cd ' 

Расширение параметра в функции заменяет все вхождения «...» на «../ ..», таким образом, это не очень чистое решение, но я думаю, что оно все еще может быть приемлемым или может быть улучшено.

0
Kamil Maciorowski

Вы не можете иметь псевдоним с пробелами. Чтобы сделать то, что вы хотите с псевдонимами, вам нужно воспользоваться этим свойством:

Если значение псевдонима, заменяющего слово, заканчивается на <blank>, оболочка должна проверить следующее командное слово на предмет замены псевдонима; этот процесс будет продолжаться до тех пор, пока не будет найдено слово, которое не является допустимым псевдонимом или значение псевдонима не заканчивается на <blank>.

( источник ), поэтому cd и последовательные ...разрешены как псевдонимы.

Вам нужны такие псевдонимы:

cd='cd ' ...='../..' ....='../../..' # and so on 

Но тогда, если вам случится иметь каталог с именем lsи вы введете его cd ls, то lsон также будет подвержен замене псевдонима. Если lsэто псевдоним, это будет иметь неприятные последствия.

Следовательно, подход чистого псевдонима неверен. Эта функция будет делать (используйте ее без вышеуказанных псевдонимов):

cd() { if [ "$#" -eq 0 ]; then command cd elif [ "$(printf '%s' "$1" | wc -l)" -eq 0 ]; then command cd "$(printf '%s' "$1" | sed '/^\.\.\+$/ ')"; else command cd "$1" fi } 

sedполучает аргумент, переданный функции, и изменяет его, если он состоит из двух или более точек; инструмент удаляет первую точку и заменяет каждую точку (слева) на ../.

Есть дополнительная логика:

  • [ "$#" -eq 0 ]позволяет подошве cd(без аргументов) работать как надо.
  • [ "$(printf '%s' "$1" | wc -l)" -eq 0 ]чтобы предотвратить, sedчтобы изменить имена каталогов многоканальных (например, foo<newline>.....которая является допустимым именем). Обратите внимание, что для обычных имен (не содержащих символов новой строки) wc -lвозвращается 0(нет 1, POSIX не рассматривает «строку» без завершения новой строки как строку), поэтому мы проверяем 0.

И есть странность:

  • В s|..|.|первых двух точках это не буквальные точки, это регулярное выражение. Можно сказать, что так и должно быть, s|\.\.|.|но обратите внимание, /^\.\.\+$/что во-первых, в строке есть только точки. То же самое относится и к первой точке в s|.|../|g.
Почему вы делаете `` printf '% s' "$ 1" | `` вместо `` <<< "$ 1" ``? Просто для POSIX? Scott 5 лет назад 0
@ Скотт Да, для POSIX. Мой первый (не опубликованный) черновик использовал `<<<`. Kamil Maciorowski 5 лет назад 0