Bash: pobiera ścieżkę bezwzględną podaną względną

Czy istnieje polecenie, aby pobrać ścieżkę bezwzględną podaną ścieżką względną?

Na przykład chcę, aby $line zawierała ścieżkę bezwzględną KAŻDEGO pliku w katalogu ./etc/

find ./ -type f | while read line; do
   echo $line
done
Author: xuhdev, 2010-11-14

16 answers

Użycie:

find $(pwd)/ -type f

Aby pobrać wszystkie pliki lub

echo $(pwd)/$line

Aby wyświetlić pełną ścieżkę (jeśli względna ścieżka ma znaczenie)

 42
Author: mpapis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-13 23:34:39

Spróbuj realpath.

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

Odpowiedź pochodzi z " polecenie bash/fish do wypisania bezwzględnej ścieżki do pliku ".

 92
Author: epere4,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:25

Jeśli masz zainstalowany pakiet coreutils, możesz użyć readlink -f relative_file_name, aby odzyskać absolutny (z rozwiązanymi wszystkimi dowiązaniami symbolicznymi)

 85
Author: Moritz Bunkus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-13 13:13:50
#! /bin/sh
echo "$(cd "$(dirname "$1")"; pwd)/$(basename "$1")"

UPD niektóre wyjaśnienia

  1. ten skrypt otrzymuje ścieżkę względną jako argument "$1"
  2. następnie otrzymujemy dirname część tej ścieżki (możesz przekazać do tego skryptu katalog lub plik): dirname "$1"
  3. następnie cd "$(dirname "$1") do tego względnego katalogu i uzyskujemy dla niego ścieżkę absolutną, uruchamiając pwd polecenie powłoki
  4. następnie dodajemy basename do ścieżki absolutnej: $(basename "$1")
  5. jako ostatni krok możemy echo to
 35
Author: Eugen Konkov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-05 10:00:58

Jeśli to coś warte, głosowałem za wybraną odpowiedzią, ale chciałem podzielić się rozwiązaniem. Minusem jest to, że jest to tylko Linux - spędziłem około 5 minut próbując znaleźć odpowiednik OSX przed przejściem do Stack overflow. Na pewno gdzieś tam jest.

Na Linuksie można używać readlink -e w połączeniu z dirname.

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

/etc/

A potem używasz siostry dirname, basename, aby po prostu nazwa pliku

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

passwd

Put it all razem..

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

/etc/passwd

Jesteś bezpieczny, jeśli celujesz w katalog, basename nic nie zwróci i skończysz z podwójnymi ukośnikami w końcowym wyjściu.

 26
Author: synthesizerpatel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-12 17:32:46

Myślę, że to jest najbardziej przenośne:

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

Nie powiedzie się, jeśli ścieżka nie istnieje.

 18
Author: Ernest A,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-28 22:43:44

realpath jest chyba najlepszy

Ale ...

Pierwsze pytanie było bardzo mylone na początku, z przykładzie słabo związane z pytaniem, jak stwierdzono.

Wybrana odpowiedź faktycznie odpowiada podanemu przykładowi, a nie w ogóle pytanie w tytule. Pierwszym poleceniem jest odpowiedź (czy to naprawdę ? Wątpię), i równie dobrze poradziłby sobie bez"/". I nie widzę co robi drugie dowództwo.

Kilka kwestii jest mieszanych :

  • Zmiana względnej nazwy ścieżki na absolutną, niezależnie od tego oznacza, prawdopodobnie nic. (zazwyczaj, jeśli wydasz polecenie takie jak touch foo/bar, pathname foo/bar musi istnieć dla Ciebie i być ewentualnie użyte w obliczenia, zanim plik zostanie faktycznie utworzony.)

  • Może istnieć kilka bezwzględnych ścieżek oznaczających ten sam plik (lub potencjalnym pliku), zwłaszcza ze względu na dowiązania symboliczne (dowiązania symboliczne) na drodze, ale być może z innych powodów (a urządzenie może być montowane dwa razy jako Tylko do odczytu). Można lub nie chce się rozstrzygnąć explicity takie dowiązania symboliczne.

  • Przejście do końca łańcucha dowiązań symbolicznych do dowiązania nie-symbolicznego plik lub nazwa. To może, ale nie musi, dać bezwzględną nazwę ścieżki, w zależności od tego, jak to się robi. I ktoś może, lub nie chce przekształć go w ścieżkę bezwzględną.

Komenda readlink foo bez opcji daje odpowiedź tylko wtedy, gdy jej argument foo jest dowiązaniem symbolicznym, a odpowiedź jest wartość tego symlink. Nie ma innego linku. Odpowiedź może być ścieżką względną: niezależnie od wartości argumentu dowiązania symbolicznego.

Jednak readlink ma opcje (- f-E lub-M), które będą działać dla wszystkich plików, i podać jedną ścieżkę bezwzględną (tą bez dowiązań symbolicznych) do plik faktycznie oznaczony argumentem.

To działa dobrze dla wszystkiego, co nie jest dowiązaniem symbolicznym, choć można chęć użycia bezwzględnej ścieżki bez rozwiązywania pośredniego dowiązania symboliczne na ścieżce. Jest to wykonywane przez polecenie realpath -s foo

W przypadku argumentu dowiązania symbolicznego, {[5] } z jego opcjami będzie ponownie rozwiąż wszystkie dowiązania symboliczne na bezwzględnej ścieżce do argumentu, ale obejmie również wszystkie dowiązania symboliczne, które mogą być napotkane przez po wartości argumentu. Możesz tego nie chcieć, jeśli chcesz bezwzględna ścieżka do samego argumentu dowiązania symbolicznego, a nie do tego, co może łączyć się z. Ponownie, jeśli foo jest dowiązaniem symbolicznym, realpath -s foo będzie uzyskać ścieżkę bezwzględną bez rozwiązywania dowiązań symbolicznych, w tym the one podane jako argument.

Bez opcji -s, realpath robi prawie to samo co readlink, z wyjątkiem zwykłego odczytu wartości odnośnika, a także kilku inne rzeczy. Nie jest dla mnie jasne dlaczego readlink ma swoje opcji, tworząc pozornie niepożądaną redundancję z realpath.

[[16]}eksploracja sieci nie mówi wiele więcej, poza tym, że może być pewne różnice między systemami.

Wniosek: realpath jest najlepszym poleceniem do użycia, z najbardziej elastyczność, przynajmniej w odniesieniu do żądanego tutaj zastosowania.

 9
Author: babou,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-21 06:44:20

ODPOWIEDŹ Eugena nie do końca mi odpowiadała, ale to się udało:

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

Na marginesie, Twój bieżący katalog roboczy nie ma wpływu.

 4
Author: biomiker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-13 20:45:43

W przypadku find najprościej jest podać absolutną ścieżkę do wyszukiwania, np.:

find /etc
find `pwd`/subdir_of_current_dir/ -type f
 2
Author: Arkku,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-13 23:33:04

Jeśli używasz bash na Mac OS X, który nie istnieje ani realpath ani jego readlink może wydrukować ścieżkę bezwzględną, możesz mieć wybór, ale kodować własną wersję, aby ją wydrukować. Oto moja realizacja:

(pure bash)

abspath(){
  local thePath
  if [[ ! "$1" =~ ^/ ]];then
    thePath="$PWD/$1"
  else
    thePath="$1"
  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[*]}"
)
}

(use gawk)

abspath_gawk() {
    if [[ -n "$1" ]];then
        echo $1|gawk '{
            if(substr($0,1,1) != "/"){
                path = ENVIRON["PWD"]"/"$0
            } else path = $0
            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
}

(pure 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($0)
}

Przykład:

$ abspath I/am/.//..//the/./god/../of///.././war
/Users/leon/I/the/war
 2
Author: Meow,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-22 07:39:44

Moim ulubionym rozwiązaniem było to autorstwa @ EugenKonkov, ponieważ nie oznaczało to obecności innych narzędzi (pakiet coreutils).

Ale nie powiodło się dla ścieżek względnych "."i "..", więc oto nieco ulepszona wersja obsługująca te szczególne przypadki.

To nadal nie powiedzie się, jeśli użytkownik nie ma uprawnień do cd do katalogu nadrzędnego ścieżki względnej.

#! /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="$1"

    if [ "$target" == "." ]; then
        echo "$(pwd)"
    elif [ "$target" == ".." ]; then
        echo "$(dirname "$(pwd)")"
    else
        echo "$(cd "$(dirname "$1")"; pwd)/$(basename "$1")"
    fi
}
 2
Author: hashchange,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-10 11:38:10

To, co powiedzieli, z wyjątkiem find $PWD lub (w bash) find ~+ jest nieco wygodniejsze.

 0
Author: Tobu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-13 23:44:12

Podobne do odpowiedzi @ ernest-a, ale bez wpływu $OLDPWD lub zdefiniowania nowej funkcji można odpalić subshell (cd <path>; pwd)

$ pwd
/etc/apache2
$ cd ../cups 
$ cd -
/etc/apache2
$ (cd ~/..; pwd)
/Users
$ cd -
/etc/cups
 0
Author: fakedrake,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-13 09:26:41

Jeśli ścieżka względna jest ścieżką katalogu, spróbuj mine, powinna być najlepsza:

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

echo $absPath
 0
Author: Shunfang Lan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-13 09:37:55

Jeśli chcesz przekształcić zmienną zawierającą ścieżkę względną w ścieżkę absolutną, działa to:

   dir=`cd "$dir"`

" cd " odbija się echem bez zmiany katalogu roboczego, ponieważ jest wykonywany tutaj w pod-powłoce.

 0
Author: Eric H.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-25 05:21:42
echo "mydir/doc/ mydir/usoe ./mydir/usm" |  awk '{ split($0,array," "); for(i in array){ system("cd "array[i]" && echo $PWD") } }'
 0
Author: Josh Barton,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-21 10:50:12