Как извлечь имя непосредственного каталога вместе с именем файла? - PullRequest
2 голосов
/ 26 февраля 2010

У меня есть файл, полный путь которого похож на

/a/b/c/d/filename.txt

Если я наберу basename, я получу filename.txt. Но это имя файла не слишком уникально.

Так что было бы лучше, если бы я мог извлечь имя файла как d_filename.txt, т.е.

{immediate directory}_{basename result}

Как мне достичь этого результата?

Ответы [ 5 ]

2 голосов
/ 26 февраля 2010
file="/path/to/filename"
echo $(basename $(dirname "$file")_$(basename "$file"))

или

file="/path/to/filename"
filename="${file##*/}"
dirname="${file%/*}"
dirname="${dirname##*/}"
filename="${dirname}_${filename}"
1 голос
/ 26 февраля 2010

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

* Примечание **: цикл в настоящее время записывается в , а не , включая любые файлы в каталоге, в котором находится этот скрипт, он просматривает только подкаталоги под ним. Это было сделано, поскольку это был самый простой способ убедиться, что скрипт не включает себя в свою обработку. Если по какой-либо причине вы должны включить каталог, в котором находится скрипт, его можно изменить, чтобы приспособить это.

код

#!/bin/bash

while IFS= read -r -d $'\0' file; do
    dirpath="${file%/*}"
    filename="${file##*/}"
    temp="${dirpath}_${filename}"
    parent_file="${temp##*/}"

    printf "dir: %10s  orig: %10s  new: %10s\n" "$dirpath" "$filename" "$parent_file"
done < <(find . -mindepth 2 -type f -print0)

Тестовое дерево

$ tree -a
.
|-- a
|   |-- b
|   |   |-- bar
|   |   `-- c
|   |       |-- baz
|   |       `-- d
|   |           `-- blah
|   `-- foo
`-- parent_file.sh

выход

$ ./parent_file.sh
dir:  ./a/b/c/d  orig:       blah  new:     d_blah
dir:    ./a/b/c  orig:        baz  new:      c_baz
dir:      ./a/b  orig:        bar  new:      b_bar
dir:        ./a  orig:        foo  new:      a_foo
0 голосов
/ 28 февраля 2010

Взять пример:

 /a/1/b/c/d/file.txt
 /a/2/b/c/d/file.txt

Единственный надежный способ указать file.txt и избежать конфликтов - встроить весь путь в новое имя файла, например,

 /a/1/b/c/d/file.txt -> a_1_b_c_d_file.txt
 /a/2/b/c/d/file.txt -> a_2_b_c_d_file.txt

Вы можете пропустить часть начала, если точно знаете, что она будет общей для всех файлов, например, если вы знаете, что все файлы находятся где-то под каталогом /a выше:

 /a/1/b/c/d/file.txt -> 1_b_c_d_file.txt
 /a/2/b/c/d/file.txt -> 2_b_c_d_file.txt

Чтобы добиться этого для каждого файла:

# file="/path/to/filename.txt"
new_file="`echo \"$file\" | sed -e 's:^/::' -e 's:/:_:g'`"
# new_file -> path_to_filename.txt

Скажем, вы хотите сделать это рекурсивно в каталоге и его подкаталогах:

# dir = /a/b
( cd "$dir" && find . | sed -e 's:^\./::' | while read file ; do
  new_file="`echo \"$file\" | sed -e 's:/:_:g'`"
  echo "rename $dir/$file to $new_file"
done )

Выход:

rename /a/b/file.txt to file.txt
rename /a/b/c/file.txt to c_file.txt
rename /a/b/c/e/file.txt to c_e_file.txt
rename /a/b/d/e/file.txt to d_e_file.txt
...

Вышеприведенное легко переносимо и будет работать практически на любой системе Unix с любым вариантом sh (включая bash, ksh и т. Д.)

0 голосов
/ 26 февраля 2010

не нужно вызывать внешнюю команду

s="/a/b/c/d/filename.txt"
t=${s%/*}
t=${t##*/}
filename=${t}_${s##*/}
0 голосов
/ 26 февраля 2010
$ FILE=/a/b/c/d/f.txt
$ echo $FILE
/a/b/c/d/f.txt
$ echo $(basename ${FILE%%$(basename $FILE)})_$(basename $FILE)
d_f.txt
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...