Почему две команды cd в скрипте bash не выполняют вторую команду?

15

Я написал скрипт bash, который создает серию каталогов и клонирует проект в выбранные каталоги.

Для этого мне нужно в cdкаждый каталог ( project 1и project 2), но скрипт не переходит cdво второй каталог и не выполняет команду.

Вместо этого он останавливается после cdклонирования и в project2каталоге. Почему он не вызывает cd_project1функцию в следующем коде?

#!/bin/bash
#Get the current user name 

function my_user_name() {        
current_user=$USER
echo " Current user is $current_user"
}

#Creating useful directories

function create_useful_directories() {  
  if [[ ! -d "$scratch" ]]; then
  echo "creating relevant directory"
  mkdir -p /home/"$current_user"/Downloads/scratch/"$current_user"/project1/project2
  else
     echo "scratch directory already exists"
     :
  fi
}

#Going to project2 and cloning 

function cd_project2() {

  cd /home/"$current_user"/Downloads/scratch/"$current_user"/project1/project2 &&
  git clone https://username@bitbucket.org/teamsinspace/documentation-tests.git
  exec bash
}

#Going to project1 directory and cloning 
function cd_project1() {

  cd /home/"$current_user"/Downloads/scratch/"$current_user"/project1/ &&
  git clone https://username@bitbucket.org/teamsinspace/documentation-tests.git
  exec bash

}

#Running the functions  
function main() {

  my_user_name
  create_useful_directories
  cd_project2
  cd_project1    
}
main

Терминальный выход:

~/Downloads$. ./bash_install_script.sh    
Current user is mihi
creating relevant directory
Cloning into 'documentation-tests'...
remote: Counting objects: 125, done.
remote: Compressing objects: 100% (115/115), done.
remote: Total 125 (delta 59), reused 0 (delta 0)
Receiving objects: 100% (125/125), 33.61 KiB | 362.00 KiB/s, done.
Resolving deltas: 100% (59/59), done.
~/Downloads/scratch/mihi/project1/project2$
Дженни
источник
3
Подумайте о принятии одного из ответов. Если более одного ответа является решением вопроса - примите лучший и проголосуйте за другой.
LeonidMew
1
Привет ЛеонидМью. Извините, я не знаю, как принять ответы. Оба ответа одинаково хороши, хотя.
Дженни
5
@ Дженни, не спешите. Читать Что мне делать, когда кто-то отвечает на мой вопрос? вместо этого и действовать соответственно, когда вы удовлетворены . Просто не торопитесь, нет причин спешить. Это нормально, если вы решите за день или неделю или в другое время.
PerlDuck
2
@LeonidMew Прошло всего 45 минут с тех пор, как был задан вопрос. Ожидание дольше - это нормально, возможно, получится лучший ответ (как говорится в комментарии PerlDuck, он просто всплыл, когда я печатал)
Xen2050
6
Мне любопытно, что ты намеревался exec bashсделать.
Приостановлено до дальнейшего уведомления.

Ответы:

28

Виновными являются ваши exec bashвысказывания в некоторых ваших функциях. Это execутверждение немного странно и, во-первых, его нелегко понять. Это значит: выполнить следующую команду вместо текущей запущенной команды / оболочки / скрипта с этого момента . То есть: он заменяет текущий сценарий оболочки (в вашем случае) экземпляром bashи никогда не возвращается.

Вы можете попробовать это с оболочкой и выпустить

exec sleep 5

Это заменит вашу текущую оболочку ( bash) на команду, sleep 5 и когда эта команда вернется (через 5 секунд), ваше окно закроется, потому что оболочка была заменена на sleep 5.

То же самое с вашим сценарием: если вы добавите его exec somethingв сценарий, сценарий будет заменен на, somethingа когда он somethingостановится, весь сценарий остановится.

Просто отбросить exec bashзаявления должны сделать.

PerlDuck
источник
2
@ Дженни Приятно слышать. Анекдот: The Perl язык также имеет execзаявление с таким же поведением , и если вы положили некоторые заявления после с execзаявлением (например exec something; print "This won't run";) , то Perl будет предупреждать вас о том , что printзаявление никогда не будут выполнены.
PerlDuck
9
Кстати, поздравляю с использованием && после CD, (если вы не используете set -e). Я видел кодекс как cd tmp; rm -rf *провал ужасно
Eckes
15

От help exec:

exec: exec [-cl] [-a name] [command [arguments ...]] [redirection ...]
    Replace the shell with the given command.

    Execute COMMAND, replacing this shell with the specified program.
    ARGUMENTS become the arguments to COMMAND.  If COMMAND is not specified,
    any redirections take effect in the current shell.

Ключевое слово здесь заменить - если вы exec bashвнутри скрипта, дальнейшее выполнение скрипта не может произойти.

steeldriver
источник
0

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

cd -

Но если вы не уверены, была ли вообще выполнена cdкоманда, было бы лучше использовать команды для помещения рабочих каталогов в стек:

pushd

и вернуться к нему (даже после нескольких изменений каталога)

popd

обязательно иметь равные pushdи popdкоманды.

Бернд Вилке πφ
источник
2
Я не уверен, что вы прочитали или поняли проблемное место. Ни одна из этих команд не поможет пользователю.
труба
Я нигде не могу прочитать о необходимости выполнения некоторых команд в оболочке. Поэтому я подумал, что он вызвал bash, чтобы вернуться в стартовый каталог. Если вы настаиваете, вы можете сказать: он спросил причину пропущенного продолжения, на которое отлично отвечают другие ответы.
Бернд Вилке,