Почему "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$ 

Просто запустите:

cd /home/xxx/yyy && command_you_want

Когда вы запускаете скрипт оболочки, он запускает новый экземпляр этой оболочки (/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 

и вы будете перемещены в папку назначения.

Вы можете использовать оператор &&:

cd myDirectory && ls

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

Другой способ сделать это - реализовать ваш скрипт как функцию в 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, а не взлома)

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