В ksh93
и bash
:
$ pwd
/tmp
$ mkdir test_dir
$ mv test_dir another_name
$ cd $_
$ pwd
/tmp/another_name
$_
заменяется на последний аргумент предыдущей команды.
В качестве функции оболочки:
mvcd () {
mv -- "$1" "$2"
cd -P -- "$_"
}
Но вы также можете использовать
mvcd () {
mv -- "$1" "$2" &&
cd -P -- "$2"
}
, так как это позаботится о том, чтобы не пытаться изменить каталог, если mv
не удалось.
Двойной дефис необходим, чтобы разрешить имена, начинающиеся с дефиса. Двойной тире сигнализирует об окончании параметров командной строки и предотвращает интерпретацию имени как параметра в таких случаях.
Команда -P
с cd
необходима для того, чтобы cd
интерпретировала пути так же, как mv
(«физически» а не "логически"). Это позволяет избежать путаницы, когда новое местоположение указано с путем, который содержит ..
и пересекает символические ссылки.
Если вы перемещаете, а не просто переименовываете каталог, нужно будет разобраться со случаем, когда перемещение не связано с переименованием каталога:
mv some_dir existing_dir
Это приведет к перемещению some_dir
в существующий_каталог
, поэтому нужно
cd existing_dir/some_dir
изменить рабочий каталог на перемещенный каталог впоследствии.
Об этом позаботится следующая модифицированная функция оболочки:
mvcd () {
if [ -d "$2" ]; then
mv -- "$1" "$2" &&
cd -P -- "$2/$1"
else
mv -- "$1" "$2" &&
cd -P -- "$2"
fi
}
или "короче":
mvcd () {
if [ -d "$2" ] && mv -- "$1" "$2"; then
cd -P -- "$2/$1"
elif mv -- "$1" "$2"; then
cd -P -- "$2"
fi
}
Невозможно объединить mv
и cd
в действительно атомарный операция. Сначала должен произойти mv
, затем cd
, как бы вы на это ни смотрели, даже если вы написали это на C. Делая одно за другим (проверяя статус выхода of mv
) — правильный способ сделать это.
Это намного проще с петлей for
:
for i in 1 2 3; do
echo var$i\ =\ hello$i
done
Проверено в bash
.
В POSIX sh
вам потребуется eval
для использования переменных с динамическими именами.
i=0
while [ "$i" -le 3 ]
do
eval '
var'"$i"'="hello${i}"
echo "var$i = ${var'"$i"'}"
'
i=$((i+1))
done
echo "${var1}"
При использовании eval
очень важно убедиться, что в аргументе, переданном в eval
(, раскрываются только те переменные, которые необходимо расширить, и что их значение очищается (здесь мы знаем, что это безопасные последовательности десятичные цифры )).
Выше только два $i
расширены. Для этого мы выходим из одинарных (сильных )кавычек и вставляем $i
внутри двойных кавычек:eval '...'"$i"'...'
.
Так как очень трудно получить правильное цитирование (и опасно, если вы не ), лучше максимально ограничить использование eval
. В идеале только передать содержимое динамической переменной в статическую и/или обратно как:
i=0
while [ "$i" -le 3 ]
do
var=hello$i # $var with static name
eval "var$i=\$var" # transfer into variable with dynamic name
echo "var$i = $var" # use var with static name instead of dynamic one
# everywhere else (for which we don't need eval)
i=$((i+1))
done
echo "${var2}"
В ksh
/zsh
/bash
/yash
вы можете использовать массивы вместо (или ассоциативные массивы в ksh93
, zsh
или последние версии bash
). Обратите внимание, что индексы массивов ksh
/bash
начинаются с 0
, а массивы являются разреженными (, больше похожими на ассоциативные массивы с ключами, ограниченными положительными целыми числами ), в то время как во всех других оболочках (, включая zsh
и yash
на фронте типа Bourne -), индексы начинаются с 1, а массивы являются обычными массивами.
В ksh
/ bash
/zsh -o ksharrays
:
unset -v var
i=0; while [ "$i" -le 3 ]; do
var[i]=hello$i
echo "var[$i]=${var[i]}"
i=$((i+1))
done
echo "${var[1]}"
Или используя другое ((...))
расширение синтаксиса POSIX sh
, общее для ksh
/ zsh
/bash
:
unset -v var
i=0; while ((i <= 3)); do
var[i]=hello$i
echo "var[$i]=${var[i]}"
((++i))
done
echo "${var[2]}"
Или с ksh93
, bash
,zsh -o ksharrays
:
unset -v var
for ((i = 0; i <= 3; i++)); do
var[i]=hello$i
echo "var[$i]=${var[i]}"
done
echo "${var[3]}"