如何在shell脚本中获取目录中的文件列表?

Posted

技术标签:

【中文标题】如何在shell脚本中获取目录中的文件列表?【英文标题】:How to get the list of files in a directory in a shell script? 【发布时间】:2011-01-27 02:30:13 【问题描述】:

我正在尝试使用 shell 脚本获取目录的内容。

我的脚本是:

for entry in `ls $search_dir`; do
    echo $entry
done

其中$search_dir 是相对路径。但是,$search_dir 包含许多名称中带有空格的文件。在这种情况下,此脚本不会按预期运行。

我知道我可以使用for entry in *,但这仅适用于我当前的目录。

我知道我可以切换到那个目录,使用 for entry in * 然后再改回来,但我的特殊情况阻止了我这样做。

我有两个相对路径 $search_dir$work_dir,我必须同时处理这两个路径,读取它们在其中创建/删除文件等。

那我现在该怎么办?

PS:我使用 bash。

【问题讨论】:

【参考方案1】:
search_dir=/the/path/to/base/dir/
for entry in "$search_dir"/*
do
  echo "$entry"
done

【讨论】:

你能解释一下为什么for entry in "$search_dir/*" 不起作用吗?为什么我们需要将/* 放在引号之外? @mrgloom:因为你需要让 shell glob 通配符。 解决方案给出了完整路径。如果我只想列出当前目录中的内容怎么办? @mrgloom 如果你想这样做,你可以使用for entry in "$search_dir/*" @Anish B:停止破坏原始帖子。答案是正确的,因为它是写的【参考方案2】:

ls $search_path ./* |grep ".txt"| 而 IFS= 读取 -r 行 做 无论“$line” 完成

【讨论】:

正如目前所写,您的答案尚不清楚。请edit 添加其他详细信息,以帮助其他人了解这如何解决所提出的问题。你可以找到更多关于如何写好答案的信息in the help center。【参考方案3】:
$ pwd; ls -l
/home/victoria/test
total 12
-rw-r--r-- 1 victoria victoria    0 Apr 23 11:31  a
-rw-r--r-- 1 victoria victoria    0 Apr 23 11:31  b
-rw-r--r-- 1 victoria victoria    0 Apr 23 11:31  c
-rw-r--r-- 1 victoria victoria    0 Apr 23 11:32 'c d'
-rw-r--r-- 1 victoria victoria    0 Apr 23 11:31  d
drwxr-xr-x 2 victoria victoria 4096 Apr 23 11:32  dir_a
drwxr-xr-x 2 victoria victoria 4096 Apr 23 11:32  dir_b
-rw-r--r-- 1 victoria victoria    0 Apr 23 11:32 'e; f'

$ find . -type f
./c
./b
./a
./d
./c d
./e; f

$ find . -type f | sed 's/^\.\///g' | sort
a
b
c
c d
d
e; f

$ find . -type f | sed 's/^\.\///g' | sort > tmp

$ cat tmp
a
b
c
c d
d
e; f

变体

$ pwd
/home/victoria

$ find $(pwd) -maxdepth 1 -type f -not -path '*/\.*' | sort
/home/victoria/new
/home/victoria/new1
/home/victoria/new2
/home/victoria/new3
/home/victoria/new3.md
/home/victoria/new.md
/home/victoria/package.json
/home/victoria/Untitled Document 1
/home/victoria/Untitled Document 2

$ find . -maxdepth 1 -type f -not -path '*/\.*' | sed 's/^\.\///g' | sort
new
new1
new2
new3
new3.md
new.md
package.json
Untitled Document 1
Untitled Document 2

注意事项:

.:当前文件夹 移除 -maxdepth 1 以递归搜索 -type f :查找文件,而不是目录 (d) -not -path '*/\.*':不返回.hidden_files sed 's/^\.\///g' :从结果列表中删除前面的 ./

【讨论】:

【参考方案4】:

接受的答案不会返回带有 . 为此,请使用

for entry in "$search_dir"/* "$search_dir"/.[!.]* "$search_dir"/..?*
do
  echo "$entry"
done

【讨论】:

【参考方案5】:

这是在目录中列出文件的另一种方式(使用不同的工具,不如其他一些答案高效)。

cd "search_dir"
for [ z in `echo *` ]; do
    echo "$z"
done

echo * 输出当前目录下的所有文件。 for 循环遍历每个文件名并打印到标准输出。

此外,如果在目录中查找目录,请将其放在 for 循环中:

if [ test -d $z ]; then
    echo "$z is a directory"
fi

test -d 检查文件是否为目录。

【讨论】:

for [ z 是语法错误。 if [ test 是愚蠢和错误的。不引用 "$z" 是引用错误。 请解释一下。当我写下答案时,我成功地运行了代码。如果您要进行 necropost 至少是有用的。 要解释什么?如果您当时对此进行了测试,那么您肯定没有使用标准外壳。我已经指出了错误,甚至从这里的其他一些答案中查找正确的语法应该不难。但是看看这个演示:ideone.com/ERcu2c 并按你的心意来分叉。 如果您认为这无关紧要,因为它已经过时了,那么您就不了解 Stack Overflow 是如何工作的。对于发布此常见问题的重复内容的新用户来说,这经常 - 可能每天 - 链接为规范答案,但也可能从 Google 搜索中获得 100 倍的流量。【参考方案6】:

这是一种让我更容易理解语法的方法:

yourfilenames=`ls ./*.txt`
for eachfile in $yourfilenames
do
   echo $eachfile
done

./ 是当前工作目录,但可以替换为任何路径*.txt 返回anything.txt 您可以通过直接在终端中输入ls 命令来轻松查看将列出的内容。

基本上,您创建一个变量yourfilenames,其中包含列表命令作为单独元素返回的所有内容,然后循环遍历它。该循环创建了一个临时变量eachfile,其中包含它正在循环的变量的单个元素,在本例中为文件名。这不一定比其他答案更好,但我觉得它很直观,因为我已经熟悉 ls 命令和 for 循环语法。

【讨论】:

这适用于快速、非正式的脚本或单行脚本,但如果文件名包含换行符,它将中断,这与基于 glob 的解决方案不同。 @SorenBjornstad 感谢您的建议!我不知道文件名中允许换行 - 什么样的文件可能有它们?比如,这是经常发生的事情吗? 由于这个原因,文件名中的换行符是邪恶的,据我所知,没有正当理由使用它们。我自己从未在野外见过一只。也就是说,完全有可能通过换行符恶意构造文件名以利用这一点。 (例如,想象一个包含文件ABC 的目录。您创建名为B\nCD 的文件,然后选择删除它们。不处理此权限的软件可能会结束即使您没有这样做的权限,也要删除先前存在的文件 B 和 C。) mywiki.wooledge.org/ParsingLs 解释了这种方法的大量缺陷。您基本上不应该在脚本中使用ls。无论如何,这很愚蠢;在 ls 运行时,shell 已经扩展了通配符。【参考方案7】:
find "$search_dir" "$work_dir" -mindepth 1 -maxdepth 1 -type f -print0 | xargs -0 -I  echo ""

【讨论】:

我知道这已经很老了,但我似乎无法获得最后一个 xargs -0 -i echo "" 命令,愿意解释一下吗?特别是-i echo "" 部分是做什么的?我还从man 页面读到-i 现在已弃用,我们应该使用-I insted。 -i 用 arg 替换 谢谢!这很有用,对于像我这样思想迟钝的人来说,我认为 是由find 命令替换为匹配项的字符串。 你为什么使用xargs?默认情况下,find 打印它找到的内容...您可以删除 -print0 中的所有内容。 这样做不能很好地处理带有空格的文件条目。【参考方案8】:

这里的其他答案很好,可以回答你的问题,但这是“bash 获取目录中文件列表”的最高谷歌结果,(我正在寻找保存文件列表)所以我想我将发布该问题的答案:

ls $search_path > filename.txt

如果您只想要某种类型(例如任何 .txt 文件):

ls $search_path | grep *.txt > filename.txt

注意 $search_path 是可选的; ls > filename.txt 会做当前目录。

【讨论】:

无需使用 grep 仅获取 .txt 文件:`ls $search_path/*.txt > filename.txt'。但更重要的是,不应该使用 ls 命令的输出来解析文件名。 @VictorZamanian,你能详细说明为什么我们不应该使用ls 的输出来解析文件名吗?以前没听说过。 @samurai_jane 关于这个主题有很多链接可以提供,但这是第一个搜索结果:mywiki.wooledge.org/ParsingLs。我什至在这里看到一个关于 SO 的问题,声称不解析 ls 输出的原因是 BS 并且对此非常详尽。但是答复/答案仍然声称这是一个坏主意。看看:unix.stackexchange.com/questions/128985/…【参考方案9】:
for entry in "$search_dir"/* "$work_dir"/*
do
  if [ -f "$entry" ];then
    echo "$entry"
  fi
done

【讨论】:

以上是关于如何在shell脚本中获取目录中的文件列表?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用Ruby进行shell脚本编写?

Shell脚本判断文件是不是存在

如何使用 Ruby 编写 shell 脚本?

如何在脚本中获取进程ID

如何避免shell脚本中的单个 * 被随机替换成目录下的一个文件名

shell获取目录下最新的文件,文件是以日期命名