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

发布于 2024-08-24 19:23:29 字数 485 浏览 6 评论 0原文

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

我的脚本是:

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

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

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

我知道我可以更改到该目录,使用 输入 * 然后再更改回来,但我的特殊情况不允许我这样做。

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

那么我现在该怎么办?

PS:我用bash。

I'm trying to get the contents of a directory using shell script.

My script is:

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

where $search_dir is a relative path. However, $search_dir contains many files with whitespaces in their names. In that case, this script does not run as expected.

I know I could use for entry in *, but that would only work for my current directory.

I know I can change to that directory, use for entry in * then change back, but my particular situation prevents me from doing that.

I have two relative paths $search_dir and $work_dir, and I have to work on both simultaneously, reading them creating/deleting files in them etc.

So what do I do now?

PS: I use bash.

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

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

发布评论

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

评论(14

最偏执的依靠 2024-08-31 19:23:29
search_dir=/the/path/to/base/dir
for entry in "$search_dir"/*
do
  echo "$entry"
done
search_dir=/the/path/to/base/dir
for entry in "$search_dir"/*
do
  echo "$entry"
done
丢了幸福的猪 2024-08-31 19:23:29

这是一种语法对我来说更容易理解的方法:

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

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

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

This is a way to do it where the syntax is simpler for me to understand:

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

./ is the current working directory but could be replaced with any path
*.txt returns anything.txt
You can check what will be listed easily by typing the ls command straight into the terminal.

Basically, you create a variable yourfilenames containing everything the list command returns as a separate element, and then you loop through it. The loop creates a temporary variable eachfile that contains a single element of the variable it's looping through, in this case a filename. This isn't necessarily better than the other answers, but I find it intuitive because I'm already familiar with the ls command and the for loop syntax.

她比我温柔 2024-08-31 19:23:29

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

ls $search_path > filename.txt

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

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

请注意 $search_path 是可选的; ls> filename.txt 将执行当前目录。

The other answers on here are great and answer your question, but this is the top google result for "bash get list of files in directory", (which I was looking for to save a list of files) so I thought I would post an answer to that problem:

ls $search_path > filename.txt

If you want only a certain type (e.g. any .txt files):

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

Note that $search_path is optional; ls > filename.txt will do the current directory.

故乡的云 2024-08-31 19:23:29
for entry in "$search_dir"/* "$work_dir"/*
do
  if [ -f "$entry" ];then
    echo "$entry"
  fi
done
for entry in "$search_dir"/* "$work_dir"/*
do
  if [ -f "$entry" ];then
    echo "$entry"
  fi
done
战皆罪 2024-08-31 19:23:29
$ 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
  • < code>sed 's/^\.\///g' :从结果列表中删除前缀 ./
$ 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

Variations

$ 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

Notes:

  • . : current folder
  • remove -maxdepth 1 to search recursively
  • -type f : find files, not directories (d)
  • -not -path '*/\.*' : do not return .hidden_files
  • sed 's/^\.\///g' : remove the prepended ./ from the result list
未央 2024-08-31 19:23:29
find "${search_dir}" "${work_dir}" -mindepth 1 -maxdepth 1 -type f -print0 | xargs -0 -I {} echo "{}"
find "${search_dir}" "${work_dir}" -mindepth 1 -maxdepth 1 -type f -print0 | xargs -0 -I {} echo "{}"
逆蝶 2024-08-31 19:23:29

类似于接受的答案 - 但仅列出文件名而不是完整路径:

这似乎已经在不久前得到回答,但我想我也想贡献一个答案,仅列出所需的文件目录,而不是完整路径。

    #search_dir=/the/path/to/base/dir/
    IFS=

如果您还想过滤特定文件,您可以添加一个grep -q 语句。

    #search_dir=/the/path/to/base/dir/
    IFS=

参考资料:

有关 IFS 的更多信息,请参见 此处

有关在 shell 中查找子字符串的更多信息,请参阅 此处

\n' #for in $() splits based on IFS search_dir="$(pwd)" for entry in $(ls $search_dir) do echo $entry done

如果您还想过滤特定文件,您可以添加一个grep -q 语句。


参考资料:

有关 IFS 的更多信息,请参见 此处

有关在 shell 中查找子字符串的更多信息,请参阅 此处

\n' #for in $() splits based on IFS search_dir="$(pwd)" for entry in $(ls $search_dir) do if grep -q "File should contain this entire string" <<< $entry; then echo "$entry" fi done

参考资料:

有关 IFS 的更多信息,请参见 此处

有关在 shell 中查找子字符串的更多信息,请参阅 此处

\n' #for in $() splits based on IFS search_dir="$(pwd)" for entry in $(ls $search_dir) do echo $entry done

如果您还想过滤特定文件,您可以添加一个grep -q 语句。

参考资料:

有关 IFS 的更多信息,请参见 此处

有关在 shell 中查找子字符串的更多信息,请参阅 此处

Similar to Accepted answer - but lists only file names instead of full paths:

This seems to have been answered a while ago, but I guess I want to also contribute an answer that just lists the files in the desired directory, as opposed to the full paths.

    #search_dir=/the/path/to/base/dir/
    IFS=

If you also wanted to filter for a specific file you would add a grep -q statement.

    #search_dir=/the/path/to/base/dir/
    IFS=

References:

More information about IFS can be found here.

More information about finding substrings in shell can be found here.

\n' #for in $() splits based on IFS search_dir="$(pwd)" for entry in $(ls $search_dir) do echo $entry done

If you also wanted to filter for a specific file you would add a grep -q statement.


References:

More information about IFS can be found here.

More information about finding substrings in shell can be found here.

\n' #for in $() splits based on IFS search_dir="$(pwd)" for entry in $(ls $search_dir) do if grep -q "File should contain this entire string" <<< $entry; then echo "$entry" fi done

References:

More information about IFS can be found here.

More information about finding substrings in shell can be found here.

\n' #for in $() splits based on IFS search_dir="$(pwd)" for entry in $(ls $search_dir) do echo $entry done

If you also wanted to filter for a specific file you would add a grep -q statement.

References:

More information about IFS can be found here.

More information about finding substrings in shell can be found here.

﹏雨一样淡蓝的深情 2024-08-31 19:23:29

接受的答案不会返回带有“.”前缀的文件
要做到这一点,请使用

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

The accepted answer will not return files prefix with a '.'
To do that use

for entry in "$search_dir"/* "$search_dir"/.[!.]* "$search_dir"/..?*
do
  echo "$entry"
done
七颜 2024-08-31 19:23:29

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

除了@Ignacio Vazquez-Abrams 得到最多支持的答案之外,还可以考虑以下解决方案,这些解决方案也都有效,具体取决于你想做什么。请注意,您可以将 "path/to/some/dir" 替换为 .,以便在当前目录中搜索。

1. 列出不同的使用 findls 的文件类型

参考:

  1. 有关 find,请参阅 这个答案。另请参阅我的评论
  2. 对于 ls,请参阅 linuxhandbook.com:如何仅列出 Linux 中的目录< /a>

提示:对于下面的任何 find 示例,如果您希望对其进行排序,可以将输出通过管道传输到 sort -V

示例:

find . -maxdepth 1 -type f | sort -V

仅列出常规文件-type f)1 级深度:

# General form
find "path/to/some/dir" -maxdepth 1 -type f

# In current directory
find . -maxdepth 1 -type f

仅列出符号链接 (-type l) 1 级深:

# General form
find "path/to/some/dir" -maxdepth 1 -type l

# In current directory
find . -maxdepth 1 -type l

仅列出目录 (-type d) 1 级深:< /strong>

请注意,对于此处的 find 示例,我们还添加了 -mindepth 1 以排除当前目录 .,这将否则将在目录列表的顶部打印为 . 。请参阅此处:如何从查找“type d”中排除此/当前/点文件夹

# General form
find "path/to/some/dir" -mindepth 1 -maxdepth 1 -type d

# In current directory
find . -mindepth 1 -maxdepth 1 -type d

# OR, using `ls`:
ls -d

结合上面的一些内容:仅列出常规文件符号链接-type f,l)1层深:

使用逗号(,) 来分隔 -type 的参数:

# General form
find "path/to/some/dir" -maxdepth 1 -type f,l

# In current directory
find . -maxdepth 1 -type f,l

2. 将任何命令的输出捕获到 bash 索引数组中,其中元素由换行符分隔 (\n)

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

这是通过告诉 bash 根据换行符 \n 而不是空格字符分隔字符串中的元素来解决的 - 这是默认的 IFS (内部字段分隔符 - -参见 Bash 脚本中 IFS 的含义 ) bash 使用的变量。为此,我建议使用 mapfile 命令。

每当您想要将字符串读入 bash 数组时,名为 shellscript 的 bash 脚本静态代码分析工具建议使用 mapfileread -r,基于换行符 (\n) 分隔元素。请参阅:https://github.com/koalaman/shellcheck/wiki/SC2206

更新:要查看如何使用 mapfileread -r 执行此操作的示例,请参阅我的答案:如何将多行字符串读入常规 bash“索引”数组我现在更喜欢使用 read -r 而不是 mapfile,因为 mapfile 会将任何空行保留为数组中的元素,如果任何存在,这是我不想要的,而 read -r [再次,我现在的偏好]不会将空行保留为数组中的元素。

(回到我原来的答案:)

以下是如何使用 mapfile 命令将换行符分隔的字符串转换为常规 bash“索引”数组

# Capture the output of `ls -1` into a regular bash "indexed" array.
# - includes both files AND directories!
mapfile -t allfilenames_array <<< "$(ls -1)"
# Capture the output of `find` into a regular bash "indexed" array
# - includes directories ONLY!
# Note: for other `-type` options, see `man find`.
mapfile -t dirnames_array \
    <<< "$(find . -mindepth 1 -maxdepth 1 -type d | sort -V)"

注意:

  1. 我们使用 ls -1 (即“破折号数字_one”)将每个文件名放在自己的行上,从而通过换行符 \n 字符将它们分开。
  2. 如果您想用 Google 搜索它,<<< 在 bash 中称为“此处字符串”。
  3. 请参阅 mapfile --helphelp mapfile 获取帮助。

完整代码示例:

来自文件array_list_all_files_and_directories.sh 在我的 eRCaGuy_hello_world 存储库中:

echo "Output of 'ls -1'"
echo "-----------------"
ls -1
echo ""

# Capture the output of `ls -1` into a regular bash "indexed" array.
# - includes both files AND directories!
mapfile -t allfilenames_array <<< "$(ls -1)"
# Capture the output of `find` into a regular bash "indexed" array
# - includes directories ONLY!
# Note: for other `-type` options, see `man find` and see my answer here:
# https://stackoverflow.com/a/71345102/4561887
mapfile -t dirnames_array \
    <<< "$(find . -mindepth 1 -maxdepth 1 -type d | sort -V)"

# Get the number of elements in each array
allfilenames_array_len="${#allfilenames_array[@]}"
dirnames_array_len="${#dirnames_array[@]}"

# 1. Now manually print all elements in each array

echo "All filenames (files AND dirs) (count = $allfilenames_array_len):"
for filename in "${allfilenames_array[@]}"; do
    echo "    $filename"
done
echo "Dirnames ONLY (count = $dirnames_array_len):"
for dirname in "${dirnames_array[@]}"; do
    # remove the `./` from the beginning of each dirname
    dirname="$(basename "$dirname")"
    echo "    $dirname"
done
echo ""

# OR, 2. manually print the index number followed by all elements in the array

echo "All filenames (files AND dirs) (count = $allfilenames_array_len):"
for i in "${!allfilenames_array[@]}"; do
    printf "  %3i: %s\n" "$i" "${allfilenames_array["$i"]}"
done
echo "Dirnames ONLY (count = $dirnames_array_len):"
for i in "${!dirnames_array[@]}"; do
    # remove the `./` from the beginning of each dirname
    dirname="$(basename "${dirnames_array["$i"]}")"
    printf "  %3i: %s\n" "$i" "$dirname"
done
echo ""

这是上面运行的代码块的示例输出在我的 eRCaGuy_hello_world/python 目录内/github.com/ElectricRCAaircraftGuy/eRCaGuy_hello_world" rel="nofollow noreferrer">eRCaGuy_hello_world 仓库:

eRCaGuy_hello_world/python$ ../bash/array_list_all_files_and_directories.sh
Output of 'ls -1'
-----------------
autogenerate_c_or_cpp_code.py
autogenerated
auto_white_balance_img.py
enum_practice.py
raw_bytes_practice.py
slots_practice
socket_talk_to_ethernet_device.py
textwrap_practice_1.py
yaml_import

All filenames (files AND dirs) (count = 9):
    autogenerate_c_or_cpp_code.py
    autogenerated
    auto_white_balance_img.py
    enum_practice.py
    raw_bytes_practice.py
    slots_practice
    socket_talk_to_ethernet_device.py
    textwrap_practice_1.py
    yaml_import
Dirnames ONLY (count = 3):
    autogenerated
    slots_practice
    yaml_import

All filenames (files AND dirs) (count = 9):
    0: autogenerate_c_or_cpp_code.py
    1: autogenerated
    2: auto_white_balance_img.py
    3: enum_practice.py
    4: raw_bytes_practice.py
    5: slots_practice
    6: socket_talk_to_ethernet_device.py
    7: textwrap_practice_1.py
    8: yaml_import
Dirnames ONLY (count = 3):
    0: autogenerated
    1: slots_practice
    2: yaml_import

How to get the list of files in a directory in a shell script?

In addition to the most-upvoted answer by @Ignacio Vazquez-Abrams, consider the following solutions which also all work, depending on what you are trying to do. Note that you can replace "path/to/some/dir" with . in order to search in the current directory.

1. List different types of files using find and ls

References:

  1. For find, see this answer. See also my comment here.
  2. For ls, see linuxhandbook.com: How to List Only Directories in Linux

Tip: for any of the find examples below, you can pipe the output to sort -V if you'd like it sorted.

Example:

find . -maxdepth 1 -type f | sort -V

List only regular files (-type f) 1 level deep:

# General form
find "path/to/some/dir" -maxdepth 1 -type f

# In current directory
find . -maxdepth 1 -type f

List only symbolic links (-type l) 1 level deep:

# General form
find "path/to/some/dir" -maxdepth 1 -type l

# In current directory
find . -maxdepth 1 -type l

List only directories (-type d) 1 level deep:

Note that for the find example here, we also add -mindepth 1 in order to exclude the current directory, ., which would be printed as . at the top of the directory list otherwise. See here: How to exclude this / current / dot folder from find "type d"

# General form
find "path/to/some/dir" -mindepth 1 -maxdepth 1 -type d

# In current directory
find . -mindepth 1 -maxdepth 1 -type d

# OR, using `ls`:
ls -d

Combine some of the above: list only regular files and symbolic links (-type f,l) 1 level deep:

Use a comma (,) to separate arguments to -type:

# General form
find "path/to/some/dir" -maxdepth 1 -type f,l

# In current directory
find . -maxdepth 1 -type f,l

2. Capture the output of any command into a bash indexed array, with elements separated by the newline char (\n)

However, $search_dir contains many files with whitespaces in their names. In that case, this script does not run as expected.

This is solved by telling bash to separate elements in the string based on the newline char \n instead of the space char--which is the default IFS (Internal Field Separator--see The Meaning of IFS in Bash Scripting) variable used by bash. To do this, I recommend using the mapfile command.

The bash script static code analyzer tool named shellscript recommends using mapfile or read -r whenever you want to read in a string into a bash array, separating elements based on the newline char (\n). See: https://github.com/koalaman/shellcheck/wiki/SC2206.

Update: to see examples of how to do this with both mapfile and read -r see my answer here: How to read a multi-line string into a regular bash "indexed" array. I now prefer to use read -r instead of mapfile, because mapfile will KEEP any empty lines as elements in the array, if any exist, which I do NOT want, whereas read -r [again, my preference now] will NOT keep empty lines as elements in the array.

(Back to my original answer:)

Here is how to convert a newline-separated string into a regular bash "indexed" array with the mapfile command.

# Capture the output of `ls -1` into a regular bash "indexed" array.
# - includes both files AND directories!
mapfile -t allfilenames_array <<< "$(ls -1)"
# Capture the output of `find` into a regular bash "indexed" array
# - includes directories ONLY!
# Note: for other `-type` options, see `man find`.
mapfile -t dirnames_array \
    <<< "$(find . -mindepth 1 -maxdepth 1 -type d | sort -V)"

Notes:

  1. We use ls -1 (that's a "dash numeral_one") in order to put each filename on its own line, thereby separating them all by the newline \n char.
  2. If you'd like to Google it, <<< is called a "here string" in bash.
  3. See mapfile --help, or help mapfile, for help.

Full code example:

From file array_list_all_files_and_directories.sh in my eRCaGuy_hello_world repo:

echo "Output of 'ls -1'"
echo "-----------------"
ls -1
echo ""

# Capture the output of `ls -1` into a regular bash "indexed" array.
# - includes both files AND directories!
mapfile -t allfilenames_array <<< "$(ls -1)"
# Capture the output of `find` into a regular bash "indexed" array
# - includes directories ONLY!
# Note: for other `-type` options, see `man find` and see my answer here:
# https://stackoverflow.com/a/71345102/4561887
mapfile -t dirnames_array \
    <<< "$(find . -mindepth 1 -maxdepth 1 -type d | sort -V)"

# Get the number of elements in each array
allfilenames_array_len="${#allfilenames_array[@]}"
dirnames_array_len="${#dirnames_array[@]}"

# 1. Now manually print all elements in each array

echo "All filenames (files AND dirs) (count = $allfilenames_array_len):"
for filename in "${allfilenames_array[@]}"; do
    echo "    $filename"
done
echo "Dirnames ONLY (count = $dirnames_array_len):"
for dirname in "${dirnames_array[@]}"; do
    # remove the `./` from the beginning of each dirname
    dirname="$(basename "$dirname")"
    echo "    $dirname"
done
echo ""

# OR, 2. manually print the index number followed by all elements in the array

echo "All filenames (files AND dirs) (count = $allfilenames_array_len):"
for i in "${!allfilenames_array[@]}"; do
    printf "  %3i: %s\n" "$i" "${allfilenames_array["$i"]}"
done
echo "Dirnames ONLY (count = $dirnames_array_len):"
for i in "${!dirnames_array[@]}"; do
    # remove the `./` from the beginning of each dirname
    dirname="$(basename "${dirnames_array["$i"]}")"
    printf "  %3i: %s\n" "$i" "$dirname"
done
echo ""

Here is the example output of the code block just above being run inside the eRCaGuy_hello_world/python dir of my eRCaGuy_hello_world repo:

eRCaGuy_hello_world/python$ ../bash/array_list_all_files_and_directories.sh
Output of 'ls -1'
-----------------
autogenerate_c_or_cpp_code.py
autogenerated
auto_white_balance_img.py
enum_practice.py
raw_bytes_practice.py
slots_practice
socket_talk_to_ethernet_device.py
textwrap_practice_1.py
yaml_import

All filenames (files AND dirs) (count = 9):
    autogenerate_c_or_cpp_code.py
    autogenerated
    auto_white_balance_img.py
    enum_practice.py
    raw_bytes_practice.py
    slots_practice
    socket_talk_to_ethernet_device.py
    textwrap_practice_1.py
    yaml_import
Dirnames ONLY (count = 3):
    autogenerated
    slots_practice
    yaml_import

All filenames (files AND dirs) (count = 9):
    0: autogenerate_c_or_cpp_code.py
    1: autogenerated
    2: auto_white_balance_img.py
    3: enum_practice.py
    4: raw_bytes_practice.py
    5: slots_practice
    6: socket_talk_to_ethernet_device.py
    7: textwrap_practice_1.py
    8: yaml_import
Dirnames ONLY (count = 3):
    0: autogenerated
    1: slots_practice
    2: yaml_import

辞取 2024-08-31 19:23:29

获取 shellbash 目录中的文件列表,4 个技巧

一些备注

Posix shell 首先:

如果您

search_dir="/the/path to/base/dir"
for entry in "$search_dir"/* ; do

(注意使用引号,以在路径名中保留空格)

从那里开始,即使

  • 目录中没有任何内容,
  • 目录也不存在(错误的路径)
  • ,脚本执行也会继续目录中存在的内容不是文件(名为 fifo、unix 套接字、音频设备、硬盘...)。

所以下一步必须

    if [ -f "$entry" ] ;then
        printf 'Now, you could quietly do something with "%s".\n' "$entry"
        # ...
    fi
done

现在bash

bash array

我经常使用这个:

entries=("$search_dir"/*)

但是,同样的评论:这将产生一个包含 ("/the/path to/base/dir/*") 的数组 如果没有文件或路径错误。

您可以使用以下命令清除第一个错误的字段

[[ ${entries[0]} == "$search_dir/*" ]] && unset entries[0]

或者您可以对数组进行快速循环,请参见此答案的底部...

然后

for entry in "${entries[@]}";do
    if [[ -f $entry ]] ;then  # ensuring entry is a file.
        'Now, you could quietly do something with "%s".\n' "$entry"
        # ...
    fi
done

使用 bash 数组,您可以使用完整的内容显示数组的内容路径,作者:

printf ' - %s\n' "${entries[@]}"

并且,仅显示文件名:

printf ' - %s\n' "${entries[@]#$search_dir/}"

使用 globstar 进行递归:

来自 man bash

  • globstar
    如果设置,路径名扩展上下文中使用的模式**将匹配所有文件以及零个或多个目录和子目录。如果模式后跟 /,则仅目录和子目录匹配。

默认情况下,globstar 处于关闭状态:

shopt globstar 
globstar        off
shopt -s globstar 

然后

entries=("$search_dir"/**)
printf ' - %s\n' "${entries[@]#$search_dir/}"

将打印 $search_dir/ 下的每个条目。

搜索文件

快速循环数组以删除不是文件的条目。

for i in ${!entries[@]};do
    [[ -f ${entries[i]} ]] || unset entries[i]
done

然后

printf ' - %s\n' "${entries[@]#$search_dir/}"

将打印 $search_dir/ 下的每个文件

搜索文件时构建数组

如果您的 $search_dir 确实包含大量非文件条目,则最好从测试的条目构建数组:

for entry in "$search_dir"/**;do
    entries+=("$entry")
done

printf ' - %s\n' "${entries[@]#$search_dir/}"

Get list of files in a directory in shell and in bash, 4 tips

Some remarks

  • Seaching for files is not searching for entries, under Un*x, Everything is a file, so under a path, you could find sockets, devices, fifos, and lot of other things which are not files.
  • Correct accepted answer from Ignacio Vazquez-Abrams will fail if $search_dir is empty or if $search_dir doesn't exist.
  • Under , you could use arrays,
  • and use 's globstar for recursivity instead of find.

Posix shell first:

If you

search_dir="/the/path to/base/dir"
for entry in "$search_dir"/* ; do

(note the use of quote, for keeping space in path name)

From there, script execution will continue even if

  • there's nothing in directory
  • the directory doesn't exist (wrong path)
  • things presents in directory are not files (named fifo, unix socket, audio device, hard disk, ...).

So next step have to be:

    if [ -f "$entry" ] ;then
        printf 'Now, you could quietly do something with "%s".\n' "$entry"
        # ...
    fi
done

Now bash.

bash array

I often use this:

entries=("$search_dir"/*)

But, same remark: this will produce an array containing ("/the/path to/base/dir/*") in case of no file or wrong path.

You could clean 1st wrong field by using

[[ ${entries[0]} == "$search_dir/*" ]] && unset entries[0]

Or you could do a quick loop over the array, see at bottom of this answer...

Then

for entry in "${entries[@]}";do
    if [[ -f $entry ]] ;then  # ensuring entry is a file.
        'Now, you could quietly do something with "%s".\n' "$entry"
        # ...
    fi
done

With bash array, you could show the content of your array with full path, by:

printf ' - %s\n' "${entries[@]}"

And, for showing only file names:

printf ' - %s\n' "${entries[@]#$search_dir/}"

Recursion using globstar:

From man bash:

  • globstar
    If set, the pattern ** used in a pathname expansion context will match all files and zero or more directories and subdirectories. If the pattern is followed by a /, only directories and subdirectories match.

globstar is off by default:

shopt globstar 
globstar        off
shopt -s globstar 

Then

entries=("$search_dir"/**)
printf ' - %s\n' "${entries[@]#$search_dir/}"

will print every entries under $search_dir/.

Searching for files.

Quick loop over array for dropping entries which are not files.

for i in ${!entries[@]};do
    [[ -f ${entries[i]} ]] || unset entries[i]
done

Then

printf ' - %s\n' "${entries[@]#$search_dir/}"

will print every files under $search_dir/.

Building array while searching for files

If your $search_dir do hold a lot of non-file entries, you'd better build array from tested entries:

for entry in "$search_dir"/**;do
    entries+=("$entry")
done

printf ' - %s\n' "${entries[@]#$search_dir/}"
喵星人汪星人 2024-08-31 19:23:29

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

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 检查文件是否是目录。

Here's another way of listing files inside a directory (using a different tool, not as efficient as some of the other answers).

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

echo * Outputs all files of the current directory. The for loop iterates over each file name and prints to stdout.

Additionally, If looking for directories inside the directory then place this inside the for loop:

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

test -d checks if the file is a directory.

方圜几里 2024-08-31 19:23:29

使用映射文件有更简单的答案!

mapfile -t file_list < <(ls "${some_path}")

然后您可以使用 file_list 列出 some_path 中的所有内容!
如果您只想要文件列表,请使用 find 而不是 ls

Ex)


// check count.
echo "${#file_list[@]}"

// check list.
for file_name in "${file_list[@]}"; do
  echo "$file_name"
done

There is simpler answer with using mapfile!

mapfile -t file_list < <(ls "${some_path}")

Then you can use file_list list with all contents in some_path!
If you want just file list, use find instead of ls

Ex)


// check count.
echo "${#file_list[@]}"

// check list.
for file_name in "${file_list[@]}"; do
  echo "$file_name"
done

鱼忆七猫命九 2024-08-31 19:23:29

如果您已经安装了tree工具或者可以安装它,那么它是一个非常好的工具。它可以列出指定目录及其子目录中的所有文件。还可以通过多种方式过滤输出:

-a            All files are listed.
-d            List directories only.
-l            Follow symbolic links like directories.
-f            Print the full path prefix for each file.
-x            Stay on current filesystem only.
-L level      Descend only level directories deep.
-R            Rerun tree when max dir level reached.
-P pattern    List only those files that match the pattern given.
-I pattern    Do not list files that match the given pattern.

等等。只需 tree --help 即可获取更多信息。

If you have installed the tree tool or can install it, it's a pretty good tool. It can list all the files in the specified dir and its subdir. Also can filter the output in many ways:

-a            All files are listed.
-d            List directories only.
-l            Follow symbolic links like directories.
-f            Print the full path prefix for each file.
-x            Stay on current filesystem only.
-L level      Descend only level directories deep.
-R            Rerun tree when max dir level reached.
-P pattern    List only those files that match the pattern given.
-I pattern    Do not list files that match the given pattern.

etc. Just tree --help for more info.

风启觞 2024-08-31 19:23:29
ls $search_path ./* |grep ".txt"|
while IFS= read -r line
do 
   echo "$line"
done
ls $search_path ./* |grep ".txt"|
while IFS= read -r line
do 
   echo "$line"
done
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文