如何提取直接目录的名称和文件名?

发布于 2024-08-23 09:22:21 字数 391 浏览 3 评论 0原文

我有一个文件,其完整路径类似于

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

如果我执行 basename 在上面,我得到filename.txt。但这个文件名并不是太独特。

,那就更好了

{immediate directory}_{basename result}

因此,如果我可以将文件名提取为d_filename.txt,即如何实现此结果?

I have a file whose complete path is like

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

If I do a basename on it, I get filename.txt. But this filename is not too unique.

So, it would be better if I could extract the filename as d_filename.txt i.e.

{immediate directory}_{basename result}

How can I achieve this result?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

葬﹪忆之殇 2024-08-30 09:22:21
file="/path/to/filename"
echo $(basename $(dirname "$file")_$(basename "$file"))

或者

file="/path/to/filename"
filename="${file##*/}"
dirname="${file%/*}"
dirname="${dirname##*/}"
filename="${dirname}_${filename}"
file="/path/to/filename"
echo $(basename $(dirname "$file")_$(basename "$file"))

or

file="/path/to/filename"
filename="${file##*/}"
dirname="${file%/*}"
dirname="${dirname##*/}"
filename="${dirname}_${filename}"
暖阳 2024-08-30 09:22:21

该代码将从运行脚本的目录开始递归地搜索层次结构。我以这样的方式对循环进行编码,它将处理您向其抛出的任何文件名;包含空格、换行符等的文件名。

*注意**:循环当前写入包含此脚本所在目录中的任何文件,它只查看它下面的子目录。这样做是因为这是确保脚本不将自身包含在其处理中的最简单方法。如果由于某种原因您必须包含脚本所在的目录,则可以更改它以适应这种情况。

代码

#!/bin/bash

while IFS= read -r -d 

测试树

$ 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' 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)

测试树

输出

This code will recursively search through your hierarchy starting with the directory that you run the script in. I've coded the loop in such a way that it will handle any filename you throw at it; file names with spaces, newlines etc.

*Note**: the loop is currently written to not include any files in the directory that this script resides in, it only looks at subdirs below it. This was done as it was the easiest way to make sure the script does not include itself in its processing. If for some reason you must include the directory the script resides in, it can be changed to accommodate this.

Code

#!/bin/bash

while IFS= read -r -d 

Test tree

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

Output

$ ./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' 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)

Test tree

Output

弄潮 2024-08-30 09:22:21
$ 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
$ 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
℡寂寞咖啡 2024-08-30 09:22:21

不需要调用外部命令

s="/a/b/c/d/filename.txt"
t=${s%/*}
t=${t##*/}
filename=${t}_${s##*/}

don't need to call external command

s="/a/b/c/d/filename.txt"
t=${s%/*}
t=${t##*/}
filename=${t}_${s##*/}
瞳孔里扚悲伤 2024-08-30 09:22:21

举个例子:

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

以上内容具有高度可移植性,并且基本上可以在任何 sh 变体下的任何 Unix 系统上运行(包括 bashksh等)

Take the example:

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

The only reliable way to qualify file.txt and avoid conflicts is to build the entire path into the new filename, e.g.

 /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

You may be able to skip part of the beginning if you know for sure that it will be common to all files, e.g if you know that all files reside somewhere underneath the directory /a above:

 /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

To achieve this on a per-file basis:

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

Say you want do do this recursively in a directory and its subdirectories:

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

Output:

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

The above is highly portable and will run on essentially any Unix system under any variant of sh (inclusing bash, ksh etc.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文