将数组用于 ls --ignore
Using array for `ls --ignore`
我正在为我的服务器备份编写 bash 脚本。
基于我的 web root(/home),我想过滤我的 web 目录排除一些将军。
我找到了 --ignore 选项。这是我返回我想要的代码。
DIR_LIST=`ls -al $WWW_ROOT --ignore={.,..,ubuntu,test} | grep "^d" | awk '{ print }'`
echo $DIR_LIST;
但是当我尝试使用数组时,效果并不好。
EXCLUDED=(. .. test ubuntu)
STR=$(IFS=,; echo "${EXCLUDED[*]}")
DIR_LIST=`ls -al $WWW_ROOT --ignore={$STR} | grep "^d" | awk '{ print }'`
echo $DIR_LIST;
echo $STR 效果很好,但 echo $DIR_LIST 不是。
我认为支架不能正常工作。
我怎样才能按预期执行此操作?
你的想法大部分是对的,但也有一些问题。首先,ls
命令使用 shell 通配样式来扩展您的 --ignore
模式。当您明确指定它时,它工作正常。
但是当你在变量中定义它来扩展 glob 时,shell 不喜欢它。因为当 shell 展开命令行时,它会先进行 glob 展开,然后再展开变量。由于您在变量中有 glob,当它扩展变量时,它已经越过可以扩展 glob 的点,因此您的 --ignore
模式永远不会按照您期望的方式真正形成。
此外,您填充数组的方式不建议采用这种方法,因为在处理涉及 spaces/newline 或任何名称的名称时,它很脆弱( Why you shouldn't parse the output of ls(1)
)其他 shell 个元字符。
请参阅 How to exclude a directory in find .
command 以在搜索文件系统时排除目录。
这是一种不使用 ls
的方法,更糟糕的是,您使用的是 -al
标志。
#!/usr/bin/env bash
shopt -s nullglob extglob
files=(/path/to/www/directory/!(ubuntu|test)/)
declare -p files
这将显示数组分配中的文件。
如果您想遍历文件并从文件名中删除路径名而不使用来自 shell 的任何外部命令。
for f in "${files[@]}"; do echo "${f##*/}"; done
使用basename
时结果相同
for f in "${files[@]}"; do var=$(basename "$f"); echo "$var"; done
或者直接在数组中做
printf '%s\n' "${files[@]##*/}"
"${files##*/}"
是 P.E 的一种形式。参数扩展。
有在线 bash 手册,您可以在其中查找 P.E。见 Parameter Expansion
或手册页。见 PAGER='less +/^[[:space:]]*parameter\ expansion' man bash
查找 nullglob
和 extglob
参见 shell globbing
名为 files
的数组现在有您感兴趣的 data/files。
默认情况下不列出点文件,因此您不必担心,除非启用 dotglob
(默认情况下处于关闭状态)。
如果 "ubuntu" 和 "test" 是文件,它应该可以工作。如果它们是目录,则需要添加点“。” ,例如 EXCLUDED
中的“.test”或“.ubuntu”
我正在为我的服务器备份编写 bash 脚本。 基于我的 web root(/home),我想过滤我的 web 目录排除一些将军。 我找到了 --ignore 选项。这是我返回我想要的代码。
DIR_LIST=`ls -al $WWW_ROOT --ignore={.,..,ubuntu,test} | grep "^d" | awk '{ print }'`
echo $DIR_LIST;
但是当我尝试使用数组时,效果并不好。
EXCLUDED=(. .. test ubuntu)
STR=$(IFS=,; echo "${EXCLUDED[*]}")
DIR_LIST=`ls -al $WWW_ROOT --ignore={$STR} | grep "^d" | awk '{ print }'`
echo $DIR_LIST;
echo $STR 效果很好,但 echo $DIR_LIST 不是。 我认为支架不能正常工作。
我怎样才能按预期执行此操作?
你的想法大部分是对的,但也有一些问题。首先,ls
命令使用 shell 通配样式来扩展您的 --ignore
模式。当您明确指定它时,它工作正常。
但是当你在变量中定义它来扩展 glob 时,shell 不喜欢它。因为当 shell 展开命令行时,它会先进行 glob 展开,然后再展开变量。由于您在变量中有 glob,当它扩展变量时,它已经越过可以扩展 glob 的点,因此您的 --ignore
模式永远不会按照您期望的方式真正形成。
此外,您填充数组的方式不建议采用这种方法,因为在处理涉及 spaces/newline 或任何名称的名称时,它很脆弱( Why you shouldn't parse the output of ls(1)
)其他 shell 个元字符。
请参阅 How to exclude a directory in find .
command 以在搜索文件系统时排除目录。
这是一种不使用 ls
的方法,更糟糕的是,您使用的是 -al
标志。
#!/usr/bin/env bash
shopt -s nullglob extglob
files=(/path/to/www/directory/!(ubuntu|test)/)
declare -p files
这将显示数组分配中的文件。
如果您想遍历文件并从文件名中删除路径名而不使用来自 shell 的任何外部命令。
for f in "${files[@]}"; do echo "${f##*/}"; done
使用basename
for f in "${files[@]}"; do var=$(basename "$f"); echo "$var"; done
或者直接在数组中做
printf '%s\n' "${files[@]##*/}"
"${files##*/}"
是 P.E 的一种形式。参数扩展。
有在线 bash 手册,您可以在其中查找 P.E。见 Parameter Expansion
或手册页。见 PAGER='less +/^[[:space:]]*parameter\ expansion' man bash
查找 nullglob
和 extglob
参见 shell globbing
名为 files
的数组现在有您感兴趣的 data/files。
默认情况下不列出点文件,因此您不必担心,除非启用 dotglob
(默认情况下处于关闭状态)。
如果 "ubuntu" 和 "test" 是文件,它应该可以工作。如果它们是目录,则需要添加点“。” ,例如 EXCLUDED
中的“.test”或“.ubuntu”