Почему "cd" не работает в сценарии оболочки?
Я пытаюсь написать небольшой скрипт, чтобы изменить текущий каталог на каталог моего проекта:
#!/bin/bash
cd /home/tree/projects/java
Я сохранил этот файл как proj, добавил разрешение на выполнение с chmod
и скопировал его в /usr/bin
, Когда я звоню по:proj
ничего не делает. Что я делаю неправильно?
33 ответа
Сценарии оболочки запускаются внутри подоболочки, и каждая подоболочка имеет свою концепцию текущего каталога. cd
Успешно, но как только выходит подоболочка, вы возвращаетесь в интерактивную оболочку и ничего там не изменилось.
Один из способов обойти это, вместо этого использовать псевдоним:
alias proj="cd /home/tree/projects/java"
Вы не делаете ничего плохого! Вы изменили каталог, но только внутри подоболочки, которая запускает скрипт.
Вы можете запустить скрипт в текущем процессе с помощью команды "точка":
. proj
Но я бы предпочел, чтобы Грег предложил использовать псевдоним в этом простом случае.
cd
в вашем скрипте технически работали, так как он изменил каталог оболочки, в которой выполнялся скрипт, но это был отдельный процесс, раздвоенный от вашей интерактивной оболочки.
Совместимый с Posix способ решения этой проблемы - определить процедуру оболочки, а не командный сценарий, вызываемый оболочкой.
jhome () {
cd /home/tree/projects/java
}
Вы можете просто напечатать это или поместить в один из различных файлов запуска оболочки.
cd
делается внутри оболочки скрипта. Когда сценарий заканчивается, оболочка завершается, и вы остаетесь в том каталоге, в котором находились. "Исходный" сценарий, не запускайте его. Вместо:
./myscript.sh
делать
. ./myscript.sh
(Обратите внимание на точку и пробел перед именем скрипта.)
Чтобы создать скрипт bash, который перейдет в выбранный каталог:
Создать файл скрипта
#!/ Bin / ш # file: /scripts/cdjava # cd /home/askgelal/projects/java
Затем создайте псевдоним в вашем файле запуска.
#!/ Bin / ш # file /scripts/mastercode.sh # псевдоним cdjava='. / Скрипты / cdjava"
- Я создал файл запуска, в который я помещаю все свои псевдонимы и пользовательские функции.
- Затем я отправляю этот файл в свой.bashrc, чтобы он устанавливался при каждой загрузке.
Например, создайте основной файл псевдонимов / функций: /scripts/mastercode.sh
(Поместите псевдоним в этот файл.)
Затем в конце вашего файла .bashrc:
source /scripts/mastercode.sh
Теперь легко перейти в ваш каталог java, просто наберите cdjava, и вы уже там.
Ты можешь использовать .
выполнить скрипт в текущей среде оболочки:
. script_name
или, альтернативно, его более читаемый, но специфичный для оболочки псевдоним source
:
source script_name
Это позволяет избежать подоболочки и позволяет использовать любые переменные или встроенные функции (включая cd
) вместо этого повлияет на текущую оболочку.
Идея Джереми Рутена об использовании символической ссылки вызвала мысль, которая не нашла никакого другого ответа. Использование:
CDPATH=:$HOME/projects
Ведущая толстая кишка важна; это означает, что если в текущем каталоге есть каталог 'dir', то 'cd dir
"изменится к этому, а не прыгать куда-то еще. С установленным значением, как показано, вы можете сделать:
cd java
и, если в текущем каталоге нет подкаталога с именем java, он сразу приведет вас в $HOME/projects/java - без псевдонимов, без сценариев, с сомнительными командами execs или dot.
Мой $ HOME - это /Users/jleffler; мой $CDPATH это:
:/Users/jleffler:/Users/jleffler/mail:/Users/jleffler/src:/Users/jleffler/src/perl:/Users/jleffler/src/sqltools:/Users/jleffler/lib:/Users/jleffler/doc:/Users/jleffler/work
использование exec bash
в конце
Сценарий bash работает в своей текущей среде или в дочерних, но никогда в родительской среде.
Однако этот вопрос часто задают, потому что кто-то хочет остаться в приглашении bash в определенном каталоге после выполнения сценария bash из другого каталога.
Если это так, просто запустите дочерний экземпляр bash в конце скрипта:
#!/bin/bash
cd /home/tree/projects/java
exec bash
Я получил свой код для работы с помощью. <your file name>
./<your file name>
доза не работает, потому что она не меняет ваш каталог в терминале, она просто меняет каталог, специфичный для этого скрипта.
Вот моя программа
#!/bin/bash
echo "Taking you to eclipse's workspace."
cd /Developer/Java/workspace
Вот мой терминал
nova:~ Kael$
nova:~ Kael$ . workspace.sh
Taking you to eclipe's workspace.
nova:workspace Kael$
Когда вы запускаете скрипт оболочки, он запускает новый экземпляр этой оболочки (/bin/bash
). Таким образом, ваш скрипт просто запускает оболочку, меняет каталог и завершает работу. Перефразируй, cd
(и другие подобные команды) внутри сценария оболочки не влияют и не имеют доступа к оболочке, из которой они были запущены.
Вы можете сделать следующее:
#!/bin/bash
cd /your/project/directory
# start another shell and replacing the current
exec /bin/bash
РЕДАКТИРОВАТЬ: Это также может быть "пунктирной", чтобы предотвратить создание последующих оболочек.
Пример:
. ./previous_script (with or without the first line)
В моем конкретном случае мне нужно было слишком много раз переходить на один и тот же каталог. Так что на моем.bashrc (я использую Ubuntu) я добавил
1 -
$ nano ~. / bashrc
function switchp
{
cd /home/tree/projects/$1
}
2-
$ source ~ /.bashrc
3 -
$ switchp Java
Непосредственно это будет делать: cd /home/tree/projects/java
Надеюсь, это поможет!
Вы можете комбинировать псевдонимы и точечные подходы Адама и Грега, чтобы сделать что-то более динамичное -
alias project=". project"
Теперь при запуске псевдонима проекта сценарий проекта будет выполняться в текущей оболочке, а не в подоболочке.
Вы можете объединить псевдоним и скрипт,
alias proj="cd \`/usr/bin/proj !*\`"
при условии, что скрипт повторяет путь назначения. Обратите внимание, что это обратные ссылки, окружающие имя скрипта.
Например, ваш скрипт может быть
#!/bin/bash
echo /home/askgelal/projects/java/$1
Преимущество этого метода заключается в том, что сценарий может принимать любое количество параметров командной строки и выдавать различные пункты назначения, рассчитанные, возможно, сложной логикой.
Это только изменяет каталог для самого скрипта, в то время как ваш текущий каталог остается прежним.
Вы можете использовать символическую ссылку вместо этого. Это позволяет вам сделать "ярлык" для файла или каталога, так что вам нужно всего лишь напечатать что-то вроде cd my-project
,
Для быстрой навигации по каталогам, есть $CDPATH, cdargs и способы автоматической генерации псевдонимов
http://jackndempsey.blogspot.com/2008/07/cdargs.html
http://muness.blogspot.com/2008/06/lazy-bash-cd-aliaes.html
https://web.archive.org/web/1/http://articles.techrepublic.com.com/5100-10878_11-5827311.html
В вашем файле ~/.bash_profile. добавить следующую функцию
move_me() {
cd ~/path/to/dest
}
Перезапустите терминал, и вы можете ввести
move_me
и вы будете перемещены в папку назначения.
Хотя поиск сценария, который вы хотите запустить, является одним из решений, вы должны знать, что этот сценарий затем может напрямую изменить среду вашей текущей оболочки. Также невозможно передавать аргументы.
Другой способ сделать это - реализовать ваш скрипт как функцию в bash.
function cdbm() {
cd whereever_you_want_to_go
echo "Arguments to the functions were $1, $2, ..."
}
Этот метод используется autojump: http://github.com/joelthelion/autojump/wiki чтобы обеспечить вас изучением закладок каталога оболочки.
Это должно делать то, что вы хотите. Перейдите в интересующий каталог (из скрипта), а затем создайте новую оболочку bash.
#!/bin/bash
# saved as mov_dir.sh
cd ~/mt/v3/rt_linux-rt-tools/
bash
Если вы запустите это, он приведет вас к интересующему каталогу, а когда вы выйдете из него, он вернет вас в исходное место.
root@intel-corei7-64:~# ./mov_dir.sh
root@intel-corei7-64:~/mt/v3/rt_linux-rt-tools# exit
root@intel-corei7-64:~#
Это даже приведет вас к исходному каталогу при выходе (CTRL+d).
Вы можете создать функцию, как показано ниже в вашем .bash_profile
и это будет работать гладко.
Следующая функция принимает необязательный параметр, который является проектом. Например, вы можете просто запустить
cdproj
или же
cdproj project_name
Вот определение функции.
cdproj(){
dir=/Users/yourname/projects
if [ "$1" ]; then
cd "${dir}/${1}"
else
cd "${dir}"
fi
}
Не забудьте найти свой источник .bash_profile
Через некоторое время, но я сделал следующее:
создать файл с именем case
вставьте в файл следующее:
#!/bin/sh
cd /home/"$1"
сохраните это и затем:
chmod +x case
Я также создал псевдоним в моем .bashrc
:
alias disk='cd /home/; . case'
теперь, когда я печатаю:
case 12345
по сути, я печатаю:
cd /home/12345
Вы можете напечатать любую папку после 'case':
case 12
case 15
case 17
что похоже на набор:
cd /home/12
cd /home/15
cd /home/17
соответственно
В моем случае путь намного длиннее - эти парни суммировали его с ~ информацией ранее.
Использование функций профиля Bash:
Одной из особенностей профиля bash является хранение пользовательских функций, которые можно запускать в терминале или в сценариях bash, так же, как вы запускаете приложение / команды, это также можно использовать в качестве ярлыка для длинных команд.
Чтобы ваша система работала эффективно, вам нужно скопировать свою функцию в конце нескольких файлов.
/home/user/.bashrc
/home/user/.bash_profile
/root/.bashrc
/root/.bash_profile
Вы можете sudo kwrite /home/user/.bashrc /home/user/.bash_profile /root/.bashrc /root/.bash_profile
быстро редактировать / создавать эти файлы
Пример скрипта
Создание ярлыка для cd ..
с cdd
cdd() {
cd ..
}
лс ярлык
ll() {
ls -l -h
}
лс ярлык
lll() {
ls -l -h -a
}
Как:
Скопируйте свою функцию в конце ваших файлов и перезагрузите терминал, после чего вы сможете запустить cdd
или какую-то функцию, которую вы написали
Вам не нужен скрипт, только установите правильную опцию и создайте переменную окружения.
shopt -s cdable_vars
в вашем ~/.bashrc
позволяет cd
к содержанию переменных среды.
Создайте такую переменную среды:
export myjava="/home/tree/projects/java"
и вы можете использовать:
cd myjava
Если вы используете рыбу в качестве оболочки, лучшее решение - создать функцию. В качестве примера, учитывая исходный вопрос, вы можете скопировать 4 строки ниже и вставить их в командную строку вашей рыбы:
function proj
cd /home/tree/projects/java
end
funcsave proj
Это создаст функцию и сохранит ее для последующего использования. Если ваш проект изменяется, просто повторите процесс, используя новый путь.
Если вы предпочитаете, вы можете вручную добавить файл функции, выполнив следующие действия:
nano ~/.config/fish/functions/proj.fish
и введите текст:
function proj
cd /home/tree/projects/java
end
и, наконец, нажмите Ctrl+ X, чтобы выйти, а затем Y, чтобы сохранить изменения.
(ПРИМЕЧАНИЕ: первый метод использования funcsave создает для вас файл proj.fish).
Мне нужно работать в tcsh, и я знаю, что это не изящное решение, но, например, если бы мне пришлось изменить папки на путь, где одно слово отличается, все это можно сделать в псевдониме
a alias_name 'set a = `pwd`; set b = `echo $a | replace "Trees" "Tests"` ; cd $b'
Если путь всегда фиксирован, справедливо
a alias_name2 'cd path/you/always/need'
должен работать В строке выше установлен новый путь к папке
вместо того, чтобы запускать файл сценария и переходить в определенную папку,
мы можем сделать это:
-
source
или же.
определенный сценарий оболочки -
alias
команда компакт-диска - определить функцию ant cd в папку
Примеры:
. script
# or
source script
alias ghqc='cd $(ghq root)/$(ghq list | fzf)'
ghqc() {
cd $(ghq root)/$1
}
Это объединяет ответ Сержа с несвязанным ответом Дэвида. Он изменяет каталог, а затем вместо принудительного запуска оболочки bash запускает оболочку пользователя по умолчанию. Однако это требует обоих
getent
и
/etc/passwd
для обнаружения оболочки по умолчанию.
#!/usr/bin/env bash
cd desired/directory
USER_SHELL=$(getent passwd <USER> | cut -d : -f 7)
$USER_SHELL
Конечно, это все тот же недостаток создания вложенной оболочки.
Обратите внимание на обсуждение. Как мне установить рабочий каталог родительского процесса?
Он содержит некоторые хакерские ответы, например /questions/32944039/kak-mne-ustanovit-rabochij-katalog-roditelskogo-protsessa/32944050#32944050 (изменение каталога родительского процесса с помощью gdb, не делайте этого) и /questions/32944039/kak-mne-ustanovit-rabochij-katalog-roditelskogo-protsessa/32944049#32944049 (команда tailcd
который внедряет dd-имя cd во входной поток родительского процесса; ну в идеале это должно быть частью bash, а не взлома)