Bash for 循环 ls 在“(”字符处拆分行

Som*_*one 0 ls bash shell-script newlines

目前我正在编写一个 bash 脚本,它应该按照创建日期的顺序循环遍历目录中的一些文件。为此,我使用(使用真实代码而不是echo):

for i in $(ls -tr)
do
    echo $i
done
Run Code Online (Sandbox Code Playgroud)

大多数情况下都可以正常工作。

但是现在我发现了一种破坏脚本的文件类型:aha_-_a ()a.txt.

此文件名包含一个空格,后跟一个左括号“(”,这似乎会触发换行符。结果是:

aha_-_a
()a.txt
Run Code Online (Sandbox Code Playgroud)

但它应该是:

aha_-_a ()a.txt
Run Code Online (Sandbox Code Playgroud)

您知道如何获得所需的行为吗?

Sté*_*las 5

不加$(ls -tr)引号会在扩展时调用 split+glob。

拆分是基于$IFS(默认为 SPC、TAB 和 NL)的字符完成的,然后 glob 部分将在其中查找通配符并尝试扩展匹配相应模式的文件。

在这里,看起来您实际上只想拆分lsNL 字符的输出,而不是执行 glob 部分。所以应该是:

IFS=$'\n' # split on NL only
set -o noglob # disable the glob part
for f in $(ls -tr); do
  printf '%s\n' "$f"
done
Run Code Online (Sandbox Code Playgroud)

这将适用于包含 SPC 字符的文件。但是,如果文件名包含 NL 字符,它仍然不起作用。

在这里,最好是切换到zsh并执行:

for f in *(NOm); do
  printf '%s\n' "$f"
done
Run Code Online (Sandbox Code Playgroud)

Where*扩展到当前目录中按年龄反向排序的所有非隐藏文件,就像ls -rt使用Omglob 限定符一样(如果没有匹配的文件,则N(for nullglob) 避免错误)。

或者,如果您有 GNU ls,请使用bash

eval "files=($(ls --quoting-style=shell-always -rt))"
for f in "${files[@]}"; do
  printf '%s\n' "$f"
done
Run Code Online (Sandbox Code Playgroud)