Bash: получить абсолютный путь заданный относительный


есть ли команда для получения абсолютного пути с учетом относительного пути?

например, я хочу, чтобы $line содержал абсолютный путь каждого файла в dir ./etc/

find ./ -type f | while read line; do
   echo $line
done
16 86

16 ответов:

использование:

find $(pwd)/ -type f

чтобы получить все файлы или

echo $(pwd)/$line

для отображения полного пути (если относительный путь имеет значение)

попробовать realpath.

~ $ sudo apt-get install realpath
~ $ realpath .bashrc
/home/username/.bashrc

ответ приходит от "команда bash/fish для печати абсолютного пути к файлу".

Если у вас установлен пакет coreutils, вы обычно можете использовать readlink -f relative_file_name чтобы получить абсолютный (со всеми разрешенными символическими ссылками)

#! /bin/sh
echo "$(cd "$(dirname "")"; pwd)/$(basename "")"

UPD объяснения

  1. этот скрипт получает относительный путь в качестве аргумента ""
  2. тогда мы получим dirname часть этого пути (вы можете передать либо dir, либо файл в этот скрипт):dirname ""
  3. затем мы cd "$(dirname "") в этот относительный dir и получить абсолютный путь для него, запустив pwd командная оболочка
  4. после этого мы добавляем basename к абсолютному пути: $(basename "")
  5. как заключительный шаг мы echo это

для чего это стоит, я голосовал за ответ, который был выбран, но хотели бы поделиться решением. Недостатком является то, что это только Linux - я потратил около 5 минут, пытаясь найти эквивалент OSX, прежде чем перейти к переполнению стека. Я уверен, что это там, хотя.

в Linux вы можете использовать readlink -e вместе с dirname.

$(dirname $(readlink -e ../../../../etc/passwd))

доходность

/etc/

и dirnameС сестрой basename просто этот имя файла

$(basename ../../../../../passwd)

доходность

passwd

сложите все вместе..

F=../../../../../etc/passwd
echo "$(dirname $(readlink -e $F))/$(basename $F)"

доходность

/etc/passwd

вы в безопасности, если вы нацелены на каталог,basename ничего не вернуть и вы просто получите двойные косые черты в конечном итоге.

Я думаю, что это самый портативный:

abspath() {                                               
    cd "$(dirname "")"
    printf "%s/%s\n" "$(pwd)" "$(basename "")"
    cd "$OLDPWD"
}

это не удастся, если путь не существует, хотя.

realpath лучше

но ...

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

выбранный ответ фактически отвечает приведенному примеру, а не вообще вопрос в названии. Первая команда это ответ (это правда ? Я сомневаюсь), и мог бы обойтись и без '/'. И я не вижу что делает вторая команда.

несколько вопросов смешанный :

  • изменение относительного пути в абсолютный, что бы это ни было обозначает, возможно, ничего. (как правило, если вы выполняете такую команду, как touch foo/bar, в путь foo/bar должен существовать для вас, и, возможно, будут использоваться в вычисление, прежде чем файл будет фактически создан.)

  • может быть несколько абсолютных путей, которые обозначают один и тот же файл (или потенциальный файл), особенно из-за символических ссылок (symlinks) На путь, но, возможно, по другим причинам (устройство может быть монтируется дважды как только для чтения). Можно или не нужно решать эксплицитность таких символических ссылок.

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

команда readlink foo без опции дает ответ только если его аргумент foo является символической ссылкой, и этот ответ является значением этого символьная ссылка. Никакой другой ссылки не следует. Ответ может быть относительным путем: каково бы ни было значение аргумента symlink.

однако, readlink имеет опции (-f-e или-m), которые будут работать для всех файлы, и дать один абсолютный путь (тот, который без символических ссылок) файл фактически обозначается аргументом.

это прекрасно работает для всего, что не является символической ссылкой, если можно жаждать использование абсолютного пути без разрешения промежуточного символические ссылки на пути. Это делается командой realpath -s foo

в случае, если аргумент ссылки readlink со своими опциями будет снова разрешите все символические ссылки на абсолютном пути к аргументу, но это также будет включать все символические ссылки, которые могут встретиться после значения аргумента. Вы можете не хотеть этого, если вы хотите абсолютный путь к самой символической ссылке аргумента, а не к чему-либо он может ссылаться на. Опять же, если foo - символическая ссылка, realpath -s foo будет получить абсолютный путь без разрешения символьных ссылок, включая одну приведено в качестве аргумента.

без , realpath делает почти то же самое, что и readlink, за исключением простого чтения значения ссылки, а также нескольких прочие вещи. Мне просто непонятно почему readlink имеет варианты, создающие, по-видимому, нежелательную избыточность с помощью realpath.

изучение интернета не говорит намного больше, за исключением что там может быть некоторые вариации в разных системах.

вывод : realpath Это лучшая команда для использования, с наиболее гибкость, по крайней мере для использования здесь.

ответ Евгения не совсем сработал для меня, но это сделало:

    absolute="$(cd $(dirname $file); pwd)/$(basename $file)"

Примечание, ваш текущий рабочий каталог не затронут.

в случае find, вероятно, проще всего просто дать абсолютный путь для его поиска, например:

find /etc
find `pwd`/subdir_of_current_dir/ -type f

если вы используете bash на Mac OS X, который ни имеет realpath не существовало ни ее более ранних версий может напечатать абсолютный путь, вы можете иметь выбор, но закодировать свою собственную версию, чтобы распечатать его. Вот моя реализация:

(чисто Баш)

abspath(){
  local thePath
  if [[ ! "" =~ ^/ ]];then
    thePath="$PWD/"
  else
    thePath=""
  fi
  echo "$thePath"|(
  IFS=/
  read -a parr
  declare -a outp
  for i in "${parr[@]}";do
    case "$i" in
    ''|.) continue ;;
    ..)
      len=${#outp[@]}
      if ((len==0));then
        continue
      else
        unset outp[$((len-1))] 
      fi
      ;;
    *)
      len=${#outp[@]}
      outp[$len]="$i"
      ;;
    esac
  done
  echo /"${outp[*]}"
)
}

(используйте gawk)

abspath_gawk() {
    if [[ -n "" ]];then
        echo |gawk '{
            if(substr(,1,1) != "/"){
                path = ENVIRON["PWD"]"/"
            } else path = 
            split(path, a, "/")
            n = asorti(a, b,"@ind_num_asc")
            for(i in a){
                if(a[i]=="" || a[i]=="."){
                    delete a[i]
                }
            }
            n = asorti(a, b, "@ind_num_asc")
            m = 0
            while(m!=n){
                m = n
                for(i=1;i<=n;i++){
                    if(a[b[i]]==".."){
                        if(b[i-1] in a){
                            delete a[b[i-1]]
                            delete a[b[i]]
                            n = asorti(a, b, "@ind_num_asc")
                            break
                        } else exit 1
                    }
                }
            }
            n = asorti(a, b, "@ind_num_asc")
            if(n==0){
                printf "/"
            } else {
                for(i=1;i<=n;i++){
                    printf "/"a[b[i]]
                }
            }
        }'
    fi
}

(чистый BSD awk)

#!/usr/bin/env awk -f
function abspath(path,    i,j,n,a,b,back,out){
  if(substr(path,1,1) != "/"){
    path = ENVIRON["PWD"]"/"path
  }
  split(path, a, "/")
  n = length(a)
  for(i=1;i<=n;i++){
    if(a[i]==""||a[i]=="."){
      continue
    }
    a[++j]=a[i]
  }
  for(i=j+1;i<=n;i++){
    delete a[i]
  }
  j=0
  for(i=length(a);i>=1;i--){
    if(back==0){
      if(a[i]==".."){
        back++
        continue
      } else {
        b[++j]=a[i]
      }
    } else {
      if(a[i]==".."){
        back++
        continue
      } else {
        back--
        continue
      }
    }
  }
  if(length(b)==0){
    return "/"
  } else {
    for(i=length(b);i>=1;i--){
      out=out"/"b[i]
    }
    return out
  }
}

BEGIN{
  if(ARGC>1){
    for(k=1;k<ARGC;k++){
      print abspath(ARGV[k])
    }
    exit
  }
}
{
  print abspath()
}

пример:

$ abspath I/am/.//..//the/./god/../of///.././war
/Users/leon/I/the/war

мое любимое решение один по @EugenKonkov, потому что это не подразумевало наличие других утилит (пакет coreutils).

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

он по-прежнему не работает, если у пользователя нет разрешения на cd в родительский каталог относительного пути, однако.

#! /bin/sh

# Takes a path argument and returns it as an absolute path. 
# No-op if the path is already absolute.
function to-abs-path {
    local target=""

    if [ "$target" == "." ]; then
        echo "$(pwd)"
    elif [ "$target" == ".." ]; then
        echo "$(dirname "$(pwd)")"
    else
        echo "$(cd "$(dirname "")"; pwd)/$(basename "")"
    fi
}

что они сказали, кроме find $PWD или (в bash) find ~+ немного удобнее.

похоже на ответ @ernest-a, но без влияния $OLDPWD или определить новую функцию, которую вы могли бы запустить подрешетку (cd <path>; pwd)

$ pwd
/etc/apache2
$ cd ../cups 
$ cd -
/etc/apache2
$ (cd ~/..; pwd)
/Users
$ cd -
/etc/cups

если относительный путь-это путь к каталогу, то попробуйте мой, должен быть лучшим:

absPath=$(pushd ../SOME_RELATIVE_PATH_TO_Directory > /dev/null && pwd && popd > /dev/null)

echo $absPath

Если вы хотите преобразовать переменную, содержащую относительный путь в абсолютный, это работает :

   dir=`cd "$dir"`

" cd " Эхо без изменения рабочего каталога, потому что выполняется здесь в суб-оболочке.

echo "mydir/doc/ mydir/usoe ./mydir/usm" |  awk '{ split(,array," "); for(i in array){ system("cd "array[i]" && echo $PWD") } }'