Bash 用于隔离目录名称的一行
Bash one-liner for isolating directory name
在 Bash 中,v.4.3.11(1) 我有这个示例代码:
#!/bin/bash
dir=("/home/user/Documents/" "/home/user/Music/" "/home/user/Videos/" \
"/home/user/Photos/")
baseDir="/home/user/"
for i in "${!dir[@]}"
do
niceName=${dir[$i]#"$baseDir"} # removes baseDir from front part
printf "%s\n" "${niceName%"/"}" # also removes trailing slash from end
done
有没有办法将这两个命令合二为一,并且在 for 循环中只有 printf? (最好不要求助于 awk 或 sed,但没关系,如果不可避免的话)。
我尝试了各种组合,但最终遇到 "bad substitution" 错误。
例如,printf "%s\n" "${niceName=${dir[$i]#"$baseDir"%"/"}"
对我不起作用。
您可以使用 basename
,其中 returns 只是基本文件名。在这种情况下,您的文件就是目录。
#!/bin/bash
dir=("/home/user/Documents/" "/home/user/Music/" "/home/user/Videos/" "/home/user/Photos/")
for i in "${!dir[@]}"
do
echo $( basename ${dir[$i]})
done
这是一个更简单的版本。
#!/bin/bash
dir=("/home/user/Documents/" "/home/user/Music/" "/home/user/Videos/" "/home/user/Photos/")
for d in "${dir[@]}"
do
basename "$d"
done
请注意 basename 的参数需要用引号引起来,否则带有某些字符(例如空格)的目录名称会导致问题。
循环内部也可以替换为下面的 builtins-based 解决方案(更快且没有外部依赖):
d="${d%/}"
echo "${d##*/}"
如果您正在寻找 one-liner 使用替换,这将有效:
dir=("/home/user/Documents/" "/home/user/Music/" "/home/user/Videos/" \
"/home/user/Photos/")
baseDir="/home/user/"
dir=("${dir[@]%/}") ## This line removes trailing forward slashes
printf "%s\n" "${dir[@]#$baseDir}"
据我所知 bash 不处理 "double parameter expansion" (我相信 zsh 可以)。但是,您可以像这样拼凑出一个解决方案:
dir=("/home/user/Documents/" "/home/user/Music/" "/home/user/Videos/" "/home/user/Photos/")
trunk=/home/user/
echo $(dir=( "${dir[@]##${trunk}}" ); echo "${dir[@]%/}")
在 Bash 中,v.4.3.11(1) 我有这个示例代码:
#!/bin/bash
dir=("/home/user/Documents/" "/home/user/Music/" "/home/user/Videos/" \
"/home/user/Photos/")
baseDir="/home/user/"
for i in "${!dir[@]}"
do
niceName=${dir[$i]#"$baseDir"} # removes baseDir from front part
printf "%s\n" "${niceName%"/"}" # also removes trailing slash from end
done
有没有办法将这两个命令合二为一,并且在 for 循环中只有 printf? (最好不要求助于 awk 或 sed,但没关系,如果不可避免的话)。
我尝试了各种组合,但最终遇到 "bad substitution" 错误。
例如,printf "%s\n" "${niceName=${dir[$i]#"$baseDir"%"/"}"
对我不起作用。
您可以使用 basename
,其中 returns 只是基本文件名。在这种情况下,您的文件就是目录。
#!/bin/bash
dir=("/home/user/Documents/" "/home/user/Music/" "/home/user/Videos/" "/home/user/Photos/")
for i in "${!dir[@]}"
do
echo $( basename ${dir[$i]})
done
这是一个更简单的版本。
#!/bin/bash
dir=("/home/user/Documents/" "/home/user/Music/" "/home/user/Videos/" "/home/user/Photos/")
for d in "${dir[@]}"
do
basename "$d"
done
请注意 basename 的参数需要用引号引起来,否则带有某些字符(例如空格)的目录名称会导致问题。
循环内部也可以替换为下面的 builtins-based 解决方案(更快且没有外部依赖):
d="${d%/}"
echo "${d##*/}"
如果您正在寻找 one-liner 使用替换,这将有效:
dir=("/home/user/Documents/" "/home/user/Music/" "/home/user/Videos/" \
"/home/user/Photos/")
baseDir="/home/user/"
dir=("${dir[@]%/}") ## This line removes trailing forward slashes
printf "%s\n" "${dir[@]#$baseDir}"
据我所知 bash 不处理 "double parameter expansion" (我相信 zsh 可以)。但是,您可以像这样拼凑出一个解决方案:
dir=("/home/user/Documents/" "/home/user/Music/" "/home/user/Videos/" "/home/user/Photos/")
trunk=/home/user/
echo $(dir=( "${dir[@]##${trunk}}" ); echo "${dir[@]%/}")