Якщо у мене є шлях до файлу, такий як ...
/home/smith/Desktop/Test
/home/smith/Desktop/Test/
Як змінити рядок, щоб він був батьківським каталогом?
напр
/home/smith/Desktop
/home/smith/Desktop/
Якщо у мене є шлях до файлу, такий як ...
/home/smith/Desktop/Test
/home/smith/Desktop/Test/
Як змінити рядок, щоб він був батьківським каталогом?
напр
/home/smith/Desktop
/home/smith/Desktop/
Відповіді:
dir=/home/smith/Desktop/Test
parentdir="$(dirname "$dir")"
Працює, якщо є також косою косою рисою.
parentdir=$(dirname `pwd`)
... але те, що " тут бачимо ", порушено. Ось виправлення:
> pwd
/home/me
> x='Om Namah Shivaya'
> mkdir "$x" && cd "$x"
/home/me/Om Namah Shivaya
> parentdir="$(dirname "$(pwd)")"
> echo $parentdir
/home/me
Просто використовуйте echo $(cd ../ && pwd)під час роботи в каталозі, чий батьківський dir ви хочете дізнатися. Ця ланцюг також має додаткову перевагу від того, що вона не має задніх косих.
echo.
Очевидно, що батьківський каталог задається простим додаванням імені файлу dot-dot:
/home/smith/Desktop/Test/.. # unresolved path
Але ви хочете вирішити шлях (абсолютний шлях без будь-яких компонентів шляху-крапки):
/home/smith/Desktop # resolved path
Проблема з головними відповідями, які використовуються dirname, полягає в тому, що вони не працюють, коли ви вводите шлях з крапками:
$ dir=~/Library/../Desktop/../..
$ parentdir="$(dirname "$dir")"
$ echo $parentdir
/Users/username/Library/../Desktop/.. # not fully resolved
Це більш потужно :
dir=/home/smith/Desktop/Test
parentdir=`eval "cd $dir;pwd;cd - > /dev/null"`
Ви можете годувати його /home/smith/Desktop/Test/.., але також і більш складні шляхи, такі як:
$ dir=~/Library/../Desktop/../..
$ parentdir=`eval "cd $dir;pwd;cd - > /dev/null"`
$ echo $parentdir
/Users # the fully resolved path!
EDIT: Якщо це не працює, переконайтеся, що ваш файл cdне змінено, як це іноді є звичайною практикою,
$ which cd
cd is a function #cd was modified to print extra info, so use "builtin cd" to override
cd ()
{
builtin cd "$@";
ls -FGAhp
}
...
evalНЕ чудово, якщо є якийсь шанс проаналізувати введення користувача, який може перенести вас кудись, де ви не очікуєте, або не почнете поганих дій щодо вашої системи. Чи можете ви використовувати pushd $dir 2>&1 >/dev/null && pwd && popd 2>&1 >/dev/nullзамість eval?
eval: просто робіть parentdir=$(cd -- "$dir" && pwd). Оскільки cdзапуск виконується в передпласті, вам не потрібно cdповертатися туди, де ми були. Тут --є на випадок, якщо розширення $dirпочинається з дефісу. Це &&лише для того, щоб не parentdirмати порожнього вмісту, коли це cdне вдалося.
Мені подобається дуже короткий, чіткий, гарантований код. Бонусний бал, якщо він не запускає зовнішню програму, оскільки в той день, коли вам потрібно буде обробити величезну кількість записів, це буде помітно швидше.
Не впевнені, які гарантії ви маєте та хочете, тому пропонуйте все одно.
Якщо у вас є гарантії, ви можете зробити це за допомогою дуже короткого коду. Ідея полягає у використанні функції заміщення тексту bash для скорочення останньої косої риски та будь-якого іншого.
Відповідь від простих до складніших випадків оригінального питання.
P=/home/smith/Desktop/Test ; echo "${P%/*}"
/home/smith/Desktop
P=/home/smith/Desktop/Test/ ; echo "${P%/*/}/"
/home/smith/Desktop/
for P in \
/home/smith/Desktop/Test \
/home/smith/Desktop/Test/
do
P_ENDNOSLASH="${P%/}" ; echo "${P_ENDNOSLASH%/*}"
done
/home/smith/Desktop
/home/smith/Desktop
for P in \
/home/smith/Desktop/Test \
/home/smith/Desktop/Test/ \
/home/smith///Desktop////Test//
do
P_NODUPSLASH="${P//\/*(\/)/\/}"
P_ENDNOSLASH="${P_NODUPSLASH%%/}"
echo "${P_ENDNOSLASH%/*}";
done
/home/smith/Desktop
/home/smith/Desktop
/home/smith/Desktop
${BASH_SOURCE[0]}якого було б повний шлях до сценарію, якщо він не був отриманий через sourceабо ..
bash: dirname 'Test': syntax error: invalid arithmetic operator (error token is "'Test'"). Пов'язаний код також неправильний.
dirname Testз каталогу Test.
Залежно від того, чи потрібні вам абсолютні шляхи, ви можете зробити додатковий крок:
child='/home/smith/Desktop/Test/'
parent=$(dirname "$child")
abs_parent=$(realpath "$parent")
скористайтеся цим: export MYVAR="$(dirname "$(dirname "$(dirname "$(dirname $PWD)")")")"якщо ви хочете 4-й батьківський каталог
export MYVAR="$(dirname "$(dirname "$(dirname $PWD)")")"
якщо ви хочете 3-й батьківський каталог
export MYVAR="$(dirname "$(dirname $PWD)")"
якщо ви хочете 2-й батьківський каталог
потворний, але ефективний
function Parentdir()
{
local lookFor_ parent_ switch_ i_
lookFor_="$1"
#if it is not a file, we need the grand parent
[ -f "$lookFor_" ] || switch_="/.."
#length of search string
i_="${#lookFor_}"
#remove string one by one until it make sens for the system
while [ "$i_" -ge 0 ] && [ ! -d "${lookFor_:0:$i_}" ];
do
let i_--
done
#get real path
parent_="$(realpath "${lookFor_:0:$i_}$switch_")"
#done
echo "
lookFor_: $1
{lookFor_:0:$i_}: ${lookFor_:0:$i_}
realpath {lookFor_:0:$i_}: $(realpath ${lookFor_:0:$i_})
parent_: $parent_
"
}
lookFor_: /home/Om Namah Shivaya
{lookFor_:0:6}: /home/
realpath {lookFor_:0:6}: /home
parent_: /home
lookFor_: /var/log
{lookFor_:0:8}: /var/log
realpath {lookFor_:0:8}: /UNIONFS/var/log
parent_: /UNIONFS/var
lookFor_: /var/log/
{lookFor_:0:9}: /var/log/
realpath {lookFor_:0:9}: /UNIONFS/var/log
parent_: /UNIONFS/var
lookFor_: /tmp//res.log/..
{lookFor_:0:6}: /tmp//
realpath {lookFor_:0:6}: /tmp
parent_: /
lookFor_: /media/sdc8/../sdc8/Debian_Master//a
{lookFor_:0:35}: /media/sdc8/../sdc8/Debian_Master//
realpath {lookFor_:0:35}: /media/sdc8/Debian_Master
parent_: /media/sdc8
lookFor_: /media/sdc8//Debian_Master/../Debian_Master/a
{lookFor_:0:44}: /media/sdc8//Debian_Master/../Debian_Master/
realpath {lookFor_:0:44}: /media/sdc8/Debian_Master
parent_: /media/sdc8
lookFor_: /media/sdc8/Debian_Master/../Debian_Master/For_Debian
{lookFor_:0:53}: /media/sdc8/Debian_Master/../Debian_Master/For_Debian
realpath {lookFor_:0:53}: /media/sdc8/Debian_Master/For_Debian
parent_: /media/sdc8/Debian_Master
lookFor_: /tmp/../res.log
{lookFor_:0:8}: /tmp/../
realpath {lookFor_:0:8}: /
parent_: /
Почав із ідеї / коментаря Чарльз Даффі - 17 грудня 14 о 14:32 на тему Отримати назву поточного каталогу (без повного шляху) у сценарії Bash
#!/bin/bash
#INFO : /programming/1371261/get-current-directory-name-without-full-path-in-a-bash-script
# comment : by Charles Duffy - Dec 17 '14 at 5:32
# at the beginning :
declare -a dirName[]
function getDirNames(){
dirNr="$( IFS=/ read -r -a dirs <<<"${dirTree}"; printf '%s\n' "$((${#dirs[@]} - 1))" )"
for(( cnt=0 ; cnt < ${dirNr} ; cnt++))
do
dirName[$cnt]="$( IFS=/ read -r -a dirs <<<"$PWD"; printf '%s\n' "${dirs[${#dirs[@]} - $(( $cnt+1))]}" )"
#information – feedback
echo "$cnt : ${dirName[$cnt]}"
done
}
dirTree=$PWD;
getDirNames;
якщо з якоїсь - небудь причини ви зацікавлені в навігації вгору певну кількість каталогів , які ви могли б також зробити: nth_path=$(cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && cd ../../../ && pwd). Це дозволить створити 3 каталогів батьків
..", але, можливо, це не зовсім те, що ви мали на увазі.