Баш: возвращает абсолютный путь относительно

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

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

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

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 shell command
  4. после этого мы добавляем имени к абсолютному пути: $(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 лучше

но ...

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

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

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

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

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

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

команда 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, который ни имеет реального пути существовал, ни его более ранних версий можно напечатать абсолютный путь, у вас может быть выбор, но закодировать свою собственную версию для печати. Вот моя реализация:

(чисто Баш)

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).

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

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

#! /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 или определите новую функцию, которую вы можете запустить subshell (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") } }'