781
我正在尝试存储名称中包含的文件列表的名称。我将使用此列表执行一些操作,然后我将删除此列表。
我有两个选择来做到这一点。
选项1:我可以使用以下命令将列表存储在临时文件中。
ls -lart *781* | awk '{print $9}' > tempo
文件tempo
将包含列表,我将在使用后删除该文件。
选项2:如果我可以以某种方式将列表存储在变量中并使用该变量。我正在尝试下面的代码来实现这一点,但这不起作用。
filelist=`ls -lart *781* | awk '{print $9}'`
echo $filelist
但上面的代码没有给出任何输出。请帮我解决语法问题。
编辑:我正在使用 k-shell。
答案1
不要使用ls
来获取文件列表,尤其ls *
是这会给您带来大量的目录空行。
你可以使用(这并不总是好的):
for file in *781*; do
echo "$file"
done
它将保留带有空格的文件,但不能保留带有其他特殊字符的文件。
您还可以这样做:
find . -name "*781*" -print0 | while IFS="" read -r -d "" file; do
echo "$file"
done
哪个更好,但不是所有 UNIX 的标准(Linux 也可以)。
在所有情况下,请勿将文件名放在单个变量中,因为不能使用空格作为分隔符。也许你可以使用 bash 数组,如下所示:
declare -a file_array
while IFS="" read -r -d "" file; do
file_array[${#file_array[@]}]="$file"
done < <(find . -print0)
要在没有进程替换的 ksh 中工作:
typeset -a file_array
mkfifo mypipe
find . -print0 > mypipe &
while IFS="" read -r -d "" file; do
file_array[${#file_array[@]}]="$file"
done < mypipe
rm mypipe
答案2
建议,受到匿名管道的想法的启发,以及需要使用函数的输出作为数组的输入,我发现协同进程可以提供帮助。
MyFunction()
{ echo "One line" ; echo "Second line" ; echo "Third line" }
set -A array
MyFunction 'SomeInputToFunction' < /dev/null |&
while read -p -r line; do
print "READING from co-process: $line"
array[ ${#array[@]} ]="$line"
done
输出:
READING from MyFunction co-process: One line
READING from MyFunction co-process: Second line
READING from MyFunction co-process: Third line
非常感谢之前的海报! ——费尔南多·冈萨雷斯
答案3
不确定您使用的是哪个 shell,但使用的是 bash
export filelist=`ls -lart *781* | awk '{print $9}'`
echo $filelist
例如:
export filelist=`ls -l|awk '{print $4}'`
echo $filelist
root root sys nobody sys sys sys sys root sys bin root sys root other sys sys root root sys other root sys root sys sys root root
答案4
我不知道为什么你的例子不起作用。它们在这里工作——如果我使用匹配任何文件的全局表达式。请注意,如果任何匹配项可能是一个目录,并且您不想列出该目录的内容,则应该向-d
您的ls
.
您必须注意当您的 glob 表达式与任何文件都不匹配时会发生什么情况。 Bash 有一个可以启用的设置shopt -s failglob
,在这种情况下会出现错误。在其他 shell 中,或者当 bash 中未启用此选项时,您将获得 glob 表达式本身作为输出。如果您只是执行 a,echo nonmatching_expression*
您将看到结果“nonmatching_expression*”。如果这样做ls nonmatching_expression*
,ls 应该抛出一个错误。
正如所写,您的两个选项都假设文件名不包含空格。这是因为ls -l ... | awk '{print $9}'
.如果您知道您的文件名不包含任何空格,那就没问题。 (但是你为什么使用ls -l ... | awk '{print $9}'
而不是仅仅使用ls
?我假设你有一些原因在上面的例子中没有体现出来。)
如果您的文件名可能包含换行符,事情将会变得更加困难——我不会讨论在这种情况下该怎么做。如果它们不包含换行符但可能包含其他空格,那么您可以省略-l
on 标志ls
并省略到 awk 的管道。然后您的第一个选项将每行一个文件名保存到临时文件中。这些文件名可以包含空格或制表符(但不能包含换行符)。您的第二个选项还将每行一个文件名存储到变量中,但是这些将更难以使用。
如果您已将文件名列表保存到变量中,并且文件名可能包含一些空格,那么您应该确保在扩展变量时始终引用该变量:因此请使用echo "$filelist"
not echo $filelist
。
以下是我提取数据的方法:
选项1:
while IFS= read -r f; do
do_stuff_with "$f"
done < tempo
选项2:
while IFS= read -r f; do
do_stuff_with "$f"
done << EOF
$filelist
EOF
这些方法允许您在循环内执行操作(修改变量、更改目录),这些操作对脚本的其余部分可见。如果您不关心这一点,那么您可以将该while ... done
部分放在管道中,例如如下所示:
echo "$filelist" | while IFS= read -r f; do
do_stuff_with "$f"
done
在这种情况下,整个while ... done
构造在子 shell 中执行,对变量的任何修改(包括循环f
)将仅在该子 shell 内可见。
Bash 和其他一些 shell 具有数组变量。有些人发现当文件名可能包含空格时更容易使用。然而,它们的便携性较差。而且它们不能出口。 (您将您的问题标记为/environment-variables
,这对我来说意味着变量将被导出。但也许您并不是那个意思。)我不会讨论如何使用数组变量来实现您的目的。
如果您知道文件名中没有任何空格,那么最简单的方法是使用选项 2,并且可以使用以下方法:
for f in $filenames; do
do_stuff_with $f
done
这里的引号必须省略 around $filenames
,并且 around 是可选的$f
。