Изменить текущий каталог из скрипта Bash

190

Можно ли изменить текущий каталог из скрипта?

Я хочу создать утилиту для навигации по каталогам в Bash. Я создал тестовый скрипт, который выглядит следующим образом:

#!/bin/bash
cd /home/artemb

Когда я выполняю скрипт из оболочки Bash, текущий каталог не меняется. Можно ли вообще изменить текущий каталог оболочки из скрипта?

artemb
источник
2
Просто предложение по улучшению: если вы используете pushd(возможно, перенаправлено на, >/dev/nullчтобы подавить вывод) вместо cd, вы можете позже вернуться к предыдущему каталогу с помощью popd.
mklement0

Ответы:

173

Вам необходимо преобразовать ваш скрипт в функцию оболочки:

#!/bin/bash
#
# this script should not be run directly,
# instead you need to source it from your .bashrc,
# by adding this line:
#   . ~/bin/myprog.sh
#

function myprog() {
  A=$1
  B=$2
  echo "aaa ${A} bbb ${B} ccc"
  cd /proc
}

Причина в том, что у каждого процесса есть свой текущий каталог, и когда вы запускаете программу из оболочки, она запускается в новом процессе. Стандартные «cd», «pushd» и «popd» встроены в интерпретатор оболочки так, что они влияют на процесс оболочки.

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

Winden
источник
2
как бы вы сделали это в tcsh?
Джоедборг
4
+1. Одна вещь, которую я заметил, была в файле, мы должны определить функцию перед ее вызовом. Это может помочь кому-то так же неопытному, как я.
Бхушан
В чем большая разница между определением функции и созданием псевдонима?
Привет, до свидания,
1
Как только я создал этот файл myprog.sh и добавил его в .bashrc, как мне запустить скрипт? Должен ли я вызывать свою функцию из другого файла оболочки или непосредственно из оболочки? Кажется, это не работает ни в коем случае ...
Андреа Сильвестри
1
@AndreaSilvestri Либо выйдите и снова войдите, либо используйте источник .bashrc. Добавление его в .bashrc ничего не делает, пока не запущен .bashrc.
Джон Страйер,
214

Когда вы запускаете ваш скрипт, создается новый процесс, который наследует только вашу среду. Когда это заканчивается, это заканчивается. Ваша текущая среда остается такой, какая она есть.

Вместо этого вы можете запустить свой скрипт так:

. myscript.sh

.Будет оценивать сценарий в текущей среде, поэтому он может быть изменен

Норберт Хартл
источник
4
+1 потому что ты прав. Хотя я искренне сомневаюсь, что он захочет получать сценарий изменения каталога каждый раз, когда ему это нужно. Кроме того, .shрасширения полностью EW. Не используйте их.
lhunath
1
Да, обычно так лучше не использовать. Большую часть времени вы рады, что ваше нынешнее окружение не страдает. Но затем у меня есть сценарии для выполнения некоторых задач по настройке для меня, включая переход в нужное место, а затем я. их тоже. Btw. .sh это вопрос личного стиля. Я, вероятно, не использовал бы это при установке сценариев всей системы. Но в моем ~ / bin я использую их, чтобы знать, что к чему :)
Norbert Hartl
11
@lhunath Почему расширения .sh полностью eww?
Карл Притчетт
1
Для меня рассуждения в этой статье являются поддельными. Кажется, что результат был известен заранее, но найти причины этого было не так просто. Так что я отстаиваю свою точку зрения, это вопрос личного стиля, ничего больше.
Норберт Хартл,
55

В свете нечитаемости и чрезмерного усложнения ответов, я полагаю, что именно это должен делать запрашивающий

  1. добавить этот скрипт в PATH
  2. запустить скрипт как . scriptname

.(Точка) будет убедиться , что сценарий не выполняется в детской оболочки.

Стивен Пенни
источник
38

Соединяя вышесказанное, вы можете сделать псевдоним

alias your_cmd=". your_cmd"

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

MergerMan
источник
Будет ли это сохраняться при перезагрузках?
SDsolar
1
@SDsolar Вы должны добавить это в файл ~ / .bashrc, чтобы сделать его постоянным. Работает как шарм для меня.
Rafał G.
Может быть помещен в ~ / .bash_aliases
Champ
@Champ ~/.bash_aliasesне всегда получается при запуске Bash.
Матеуш Пиотровски
31

Если вы используете bash, вы можете попробовать псевдоним:

в файл .bashrc добавьте эту строку:

alias p='cd /home/serdar/my_new_folder/path/'

когда вы пишете «p» в командной строке, это изменит каталог.

Akarca
источник
1
+1 для псевдонима. Функция оболочки интересна, но ОП попросил простую навигацию с помощью CD. Я предполагаю, что большинству людей нужен скрипт, подобный этому, для навигации по веткам исходного кода, и для этого псевдонима достаточно
Брэд Дре
19

Если вы запустите скрипт bash, он будет работать в своей текущей среде или в среде своих потомков, а не в родительской.

Если цель состоит в том, чтобы запустить вашу команду: goto.sh / home / test Затем поработайте в интерактивном режиме в / home / test, один из способов - запустить интерактивную подоболочку bash в вашем скрипте:

#!/bin/bash
cd $1
exec bash

Таким образом, вы будете находиться в / home / test до выхода (выход или Ctrl + C) из этой оболочки.

Филипп Ларди
источник
Я думал, что это решило бы проблему для сценария оболочки, который я выполнял, но вместо этого он запускает оболочку и забывает, что я хотел.
vwvan
14

С помощью pushd текущий каталог помещается в стек каталогов и изменяется на данный каталог, popd получает каталог в верхней части стека и затем изменяет его.

pushd ../new/dir > /dev/null
# do something in ../new/dir
popd > /dev/null
СЕБ
источник
2
Это отвечает на мой вопрос - активное развертывание этого решения с помощью сценария инициализации S3, и оно прекрасно работает. Спасибо @seb.
19
5

Просто зайдите в

yourusername/.bashrc (or yourusername/.bash_profile on MAC) by an editor

и добавьте этот код рядом с последней строкой:

alias yourcommand="cd /the_path_you_wish"

Затем выйдите из редактора.

Затем введите:

source ~/.bashrc or source ~/.bash_profile on MAC.

Теперь вы можете использовать: yourcommand в терминале

ThangTD
источник
3

В основном мы используем, cd..чтобы вернуться из каждого каталога. Я подумал, чтобы было проще, указав количество каталогов, с которыми вам нужно возвращаться за раз. Вы можете реализовать это, используя отдельный файл сценария с помощью команды alias. Например:

code.sh

#!/bin/sh
 _backfunc(){
 if [ "$1" -eq 1 ]; then
  cd ..
 elif [ "$1" -eq 2 ]; then
  cd ../..
 elif [ "$1" -eq 3 ]; then
  cd ../../..
 elif [ "$1" -eq 4 ]; then
  cd ../../../..
 elif ["$1" -eq 10]; then
  cd /home/arun/Documents/work
 fi
 }
alias back='_backfunc'   

После использования source code.shв текущей оболочке вы можете использовать:

$back 2 

вернуться в двух шагах от текущего каталога. Подробно объяснено здесь . Там также объясняется, как поместить код в ~ / .bashrc, чтобы каждая новая открытая оболочка автоматически получала эту новую команду псевдонима. Вы можете добавить новую команду для перехода в определенные каталоги, изменив код, добавив больше if conditionsи другие аргументы. Вы также можете получить код из git здесь .

Арун Четтур
источник
Хорошее решение, так что вы никогда не испортите свой профиль bash :)
J4cK
0

Этот подход проще для меня.

Предположим, что на персональном iMac, где вы являетесь администратором, в каталоге по умолчанию, когда открывается окно командной строки, / Users / jdoe, это будет каталог для перехода: /Users/jdoe/Desktop/Mongo/db.3.2.1 / бен.

Вот шаги, которые могут сделать работу:

  1. Ви Монгобин, в который я вошел: cd /Users/jdoe/Desktop/Mongo/db.3.2.1/binкак первая строка.
  2. chmod 755 mongobin
  3. source mongobin
  4. pwd

Вуаля!

Дэниел С. Дэн
источник
0

Я также создал утилиту под названием goat, которую вы можете использовать для более удобной навигации.

Вы можете просмотреть исходный код на GitHub .

По V2.3.1 на обзорном использование выглядит следующим образом :

# Create a link (h4xdir) to a directory:
goat h4xdir ~/Documents/dev

# Follow a link to change a directory:
cd h4xdir

# Follow a link (and don't stop there!):
cd h4xdir/awesome-project

# Go up the filesystem tree with '...' (same as `cd ../../`):
cd ...

# List all your links:
goat list

# Delete a link (or more):
goat delete h4xdir lojban

# Delete all the links which point to directories with the given prefix:
goat deleteprefix $HOME/Documents

# Delete all saved links:
goat nuke

# Delete broken links:
goat fix
Матеуш Пиотровский
источник
0

Мне нравится делать одно и то же для разных проектов без запуска новой оболочки.

В твоем случае:

cd /home/artemb

Сохраните the_script как:

echo cd /home/artemb

Затем запустите его:

\`./the_script\`

Затем вы попадаете в каталог с помощью той же оболочки.

DrGamma
источник
0

Добавьте ниже строку cd в свой шеллскрипт так:

exec $SHELL
Альберто Корелла
источник
0

Объявите свой путь:

PATH='/home/artemb'     
cd ${PATH}
m_sam
источник
0

Просто напишите PWDи экспортируйте его в свой скрипт, и изменения будут сохраняться.

export PWD=/your/desired/directory
Самха»
источник