0

I use readlink to find a file's full path:

  cek=$(readlink -f "$1")
  mkdir -p  "$ydk$cek"
  mv "$1" "$ydk/$cek/$ydkfile"  

But readlink -f "$1" gives me the full path. How can I crop the full path?

For example:

  /home/test/test/2014/10/13/log.file

But I need just

  /test/2014/10/13/

How can I do it?


Judging from multiple comments:

  • The output should be the last four directory components of the full path returned by readlink.

Given:

full_path=/home/some/where/hidden/test/2014/08/29/sparefile.log

the output should be:

test/2014/08/29

(Don't build any assumption about today's date into the path trimming code.)

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
onur
  • 5,647
  • 3
  • 23
  • 46
  • 3
    Perhaps this can help you: http://stackoverflow.com/questions/2564634/bash-convert-absolute-path-into-relative-path-given-a-current-directory – aioobe Oct 13 '14 at 14:03
  • you simply want remove the `/home/test` or here is some other logic what you forgot to tell? – clt60 Oct 13 '14 at 14:06
  • 1
    How do you determine what is to be cropped from the start of the name? Is it the value in `$ydk` or `$HOME` or something else? – Jonathan Leffler Oct 13 '14 at 14:12
  • I cant determine start way. Just I know last 3 or 4 folder name, and I need to crop just last 3 or 4 folder way. – onur Oct 13 '14 at 14:16
  • 1
    If you don't know, neither do we. How can we tell whether to leave 3 or 4 components if you don't know whether you need 3 or 4 components? What is the criterion for deciding on 3 components instead of 4, or vice versa? – Jonathan Leffler Oct 13 '14 at 14:18
  • Sorry my fault. I mean just I know last 4 folder name: "/home/xxx/yyy/zzz/test/2014/10/13/". /home/xxx/yyy/zzz not static, sometimes have xxx yyy zzz, sometimez just have xxx. That's why I need to crop without last 4 /test/2014/10/13. – onur Oct 13 '14 at 14:23

2 Answers2

4

If you need the last four directory components of the full path, and if you don't have newlines in the full path, and if you have GNU grep or BSD (Mac OS X) grep with support for -o (output only the matched material) then this gives the required result:

$ cek="/home/test/test/2014/10/13/log.file"
$ echo "${cek%/*}"
/home/test/test/2014/10/13
$ echo "${cek%/*}" | grep -o -E -e '(/[^/]+){4}$'
/test/2014/10/13
$ full_path=/home/some/where/hidden/test/2014/08/29/sparefile.log
$ echo "${full_path%/*}" | grep -o -E -e '(/[^/]+){4}$'
/test/2014/08/29
$

I need path starting /201[0-9]:

/home/bla/bla2/bla3/2014/01/13/13…/2014/01/13/13….

So, you need to use grep -o again, starting with the year pattern:

echo "${fullpath%/*}" | grep -o -e '/201[0-9]/.*$'

This is much simpler; you don't even need extended regular expressions for this!

If you need the path element before the year too, then you need:

echo "{fullpath%/*}" | grep -o -e '/[^/][^/]*/201[0-9]/.*$'
Community
  • 1
  • 1
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • Thank you it's work but I have new problem now. Sometimes I need last four directory, sometimes more, its not static. But 2014/.... static path. So how can I crop when see /201 --> /2014/..... – onur Oct 15 '14 at 06:26
  • Explain your requirements precisely. Do you need the path starting at `/201[0-9]/`? Do you need the element before that and the 201x and 2 elements after it? If you can't explain precisely what you need, then (1) you can't implement what you need because you don't know, and (2) we can't help you because we don't know either. – Jonathan Leffler Oct 15 '14 at 06:29
  • I need path starting /201[0-9] : /home/bla/bla2/bla3/2014/01/13/13... -> /2014/01/13/13.... Sorry for my english. – onur Oct 15 '14 at 06:42
0

Do you really need to remove "/home" ?

cek="/home/test/test/2014/10/13/log.file"
dir=$(dirname "$cek")
echo "${dir#/home}"
/test/test/2014/10/13

Just last 4 directory components:

last4dirs() { 
    local IFS=/
    local -a components=($1)
    local l=${#components[@]}
    echo "${components[*]:l-5:4}"
}
last4dirs /home/some/where/hidden/test/2014/08/29/sparefile.log
test/2014/08/29
glenn jackman
  • 238,783
  • 38
  • 220
  • 352
  • Looks to me like `${dir#$ydk}` is more what the OP is after there. Though it isn't very clear. – Etan Reisner Oct 13 '14 at 14:07
  • The desired output seems to be missing `/home/test` from the front (only one `/test` in the output), and `log.file` from the end. It is a path fragment, but the basis for chopping the front of the path is unclear. It's not clear why you didn't use `${cek%/*}` instead of `$(dirname "$cek")`. – Jonathan Leffler Oct 13 '14 at 14:09
  • Thank you it's work. If I have more than 1 home folder, mean sometimes 1 home or test folder, sometimes 2-3 folder. How can i crop just /test/2014/10/13/ ? Mean just last 3 or 4 folder way. – onur Oct 13 '14 at 14:14
  • 1
    @volkanasr: you must tell us which variable holds the prefix (`/home/test`) that must be removed. It is then trivial: `${dir#$variable_holding_prefix_to_be_removed}`. – Jonathan Leffler Oct 13 '14 at 14:17
  • @JonathanLeffler I assume you know this but for general edification `dirname` handles edge-cases that variable substitution does not. See [this answer](http://stackoverflow.com/a/22402242/258523) for some details. In this case those edge-cases are unlikely to matter it would seem though. – Etan Reisner Oct 13 '14 at 14:35
  • 1
    @EtanReisner: I hadn't had my nose rubbed in the '`"${var%/*}" != $(dirname "$var")` issue; that's the difference between a lexical operation and a 'semantic' operation. The variable substitution is a purely textual operation, whereas `dirname` works with the semantics. In this case, the output of `readlink` is (apparently) a full path and not a relative path or simple rename — that's not guaranteed in general, though (`../../another/directory/hierarchy/target-file` is a possible output from `readlink`; you'd need a `realpath` command using the `realpath()` function to get an absolute name). – Jonathan Leffler Oct 13 '14 at 14:51