本问题已经有最佳答案,请猛点这里访问。
我需要使用bash脚本存储目录中包含的每个文件的名称,并以某种方式对其进行处理:
drwxrwxr-x 5 matteorr matteorr 4096 Jan 10 17:37 Cluster
drwxr-xr-x 2 matteorr matteorr 4096 Jan 19 10:43 Desktop
drwxrwxr-x 9 matteorr matteorr 4096 Jan 20 10:01 Developer
drwxr-xr-x 11 matteorr matteorr 4096 Dec 20 13:55 Documents
drwxr-xr-x 2 matteorr matteorr 12288 Jan 20 13:44 Downloads
drwx------ 11 matteorr matteorr 4096 Jan 20 14:01 Dropbox
drwxr-xr-x 2 matteorr matteorr 4096 Oct 18 18:43 Music
drwxr-xr-x 2 matteorr matteorr 4096 Jan 19 22:12 Pictures
drwxr-xr-x 2 matteorr matteorr 4096 Oct 18 18:43 Public
drwxr-xr-x 2 matteorr matteorr 4096 Oct 18 18:43 Templates
drwxr-xr-x 2 matteorr matteorr 4096 Oct 18 18:43 Videos
使用以下命令,我可以在所有空格之间分割ls -l的结果,然后访问包含名称的最后一个元素:
ls -l | awk '{split($0,array,"")} END{print array[9]}'
但是,它仅返回最后一行(即Videos),因此我需要在ls -l命令返回的所有行上进行迭代。
我怎样才能做到这一点?
有没有更好的方法来解决整个问题?
新增部分
要更具体地说明我需要做什么:
对于目录中包含的所有文件(如果是文件),我将不执行任何操作;如果是目录,则应将目录名称附加到其包含的所有文件中。
因此,假设视频目录具有文件:
-rwxr-xr-x 2 matteorr matteorr 4096 Oct 18 18:43 video1.mpeg
-rwxr-xr-x 2 matteorr matteorr 4096 Oct 18 18:43 Video2.wmv
我需要重命名它们,如下所示:
-rwxr-xr-x 2 matteorr matteorr 4096 Oct 18 18:43 video1_Videos.mpeg
-rwxr-xr-x 2 matteorr matteorr 4096 Oct 18 18:43 Video2_Videos.wmv
如果您关心脚本的健壮性(针对怪异文件名的健壮性),则更好的方法可能是使用find而不是ls:mywiki.wooledge.org/ParsingLs
你想做什么?
@richard-我需要存储目录的名称,然后将其附加到它包含的所有文件中
您将如何处理每个文件?
能给我举个例子吗。
@Behe-对于目录中包含的所有文件,如果它是文件,我将不执行任何操作;如果它是目录,则应将目录名附加到它包含的所有文件中。
@richard-更新的问题
追加还是前置?您想在末尾添加目录名称吗?您要在文件扩展名之后还是之前添加它?
@JohnKugelman-应该在扩展名之前但在文件名之后
请提供示例,而不是描述。我想你想做的是一个目录拼合器,例如如果您有文件ab, ac, ade, afgh,则可以将其更改为ab, ac, ad_e, af_g_h。这个对吗?
@richard-我完全不需要脚本,但是我猜可能是目录展平器。但是我举了一个例子。
您可以将我列出的所有案例添加到示例中吗?
@richard-是的,当然!但是您能帮我在您的答案中弄清楚吗?
聚会有点晚了……我添加了一个"目录扁平化"脚本,作为对我先前答案的更新。
我要去聚会了,因为我仍然不知道你要做什么。
更好的方法是使用bash通配
仅列出所有文件
echo *
或与他们做某事
for file in *; do
echo"$file" # or do something else
done
或使用bash递归4+
shopt -s globstar
for file in **/*; do
echo"$file" # or do something else
done
更新以获取目录名称并将其附加到其中的所有文件中
用echo替换mv以测试其功能。另请注意,${file##*.}假定扩展名是最后一个句点之后的所有内容,因此,如果在目录on中具有类似file.tar.gz的文件,则下面将其转换为file.tar_on.gz。据我所知,没有简单的方法可以解决此问题,尽管您可以跳过带有多个.的文件)
#!/bin/bash
d="/some/dir/to/do/this/on"
name=${d##*/} #name=on
for file in"$d"/*; do
extension=${file##*.}
filename=${file%.*}
filename=${filename##*/}
[[ -f $file ]] && mv"$file""$d/${filename}_${name}.$extension"
done
例如
> ls /some/dir/to/do/this/on
video1.mpeg Video2.wmv
> ./abovescript
> ls /some/dir/to/do/this/on
video1_on.mpeg Video2_on.wmv
说明
在bash中,您可以执行此操作
${parameter#word}删除最短匹配的前缀
${parameter##word}删除最长匹配的前缀
${parameter%word}删除最短匹配的后缀
${parameter%%word}删除最长匹配的后缀
为了删除上一句之前和之后的所有内容(*),我在下面做了
extension=${file##*.}
为了删除包括上一个周期在内的所有内容,我在下面做了(想想最短的匹配在这里是从右到左,例如*从右到左查找任何非周期文本,然后在找到一个周期时将其删除)整个部分)
filename=${file%.*}
为了删除直到最后一个/的所有内容,我在下面做了。
filename=${filename##*/}
其他注意事项:
"$d/${filename}_${name}.$extension"变量可以具有_,因此我在这里切换了几个变量的语法以使其起作用
"$d"/*直接在" $ d"中扩展到任何类型的文件(常规,目录,符号链接等)
感谢您的出色回答!我正在尝试
@Matteo没问题。如果您的文件带有多点扩展名,请在脚本上方查看我的评论。处理该问题将变得更加混乱,并且可能涉及具有已知多点扩展的数组,并对其进行测试或类似的测试。
该脚本运行正常,我能否请您多评论一下?我对所有#,%,.,,*字符感到困惑...
@Matteo更新了解释。另外,我忘记了原始脚本中相当重要的部分。如果只想播放常规文件,则应该执行[[ -f $file ]] && mv之类的操作,因为*会扩展到包括子目录在内的所有文件。
+1一些非常酷的bash技巧。我每天在这里学到新东西。今天,这个答案是"新的东西"。谢谢!注意-我修正了一些错字。请确保我没有不小心更改答案的含义。
@Floris感谢您的修复。
好问题!很高兴你问。解析ls的输出很少是正确的事情。有多种方法来处理文件列表。这取决于您要如何处理它们。
这是您可以做的一些事例。我已经使用touch作为示例命令。用您要执行的任何命令替换该命令。
要对多个文件运行命令,通常只需在命令行上传递所有文件即可。
touch /var/myapp/*
循环遍历当前目录中的文件:
for file in *; do
touch"$file"
done
要遍历另一个目录中的文件:
for file in /some/dir/*; do
touch"$file"
done
要将此处和子目录中名为*.txt的文件重命名为'* .bak',请执行以下操作:
find . -name '*.txt' -exec mv {} {}.bak \;
要删除Bob的主目录中的JPEG(该死的Bob和流浪的眼睛):
find ~bob/ -name '*.jpg' -delete
以递归方式遍历文件并对它们执行复杂的操作:
find /dir/to/search -print0 | while read -d $'\0' file; do
echo"$file"
touch"$file"
if [[ -L $file ]]; then
# $file is a symlink, do something special
fi
done
也许请注意,find -print0是不可移植的GNU find扩展。
ls -l | awk '{split($0,array,"")} {print array[9]}'
要么
ls -l | awk '{print $9}'
但是为什么不只是ls?
ks,但是我该如何遍历项目清单呢?
ls如果将输出重定向到终端以外的其他内容,则将输出放在一列中。键入ls | cat进行检查。如果您真的不相信自动终端检测将起作用,则可以使用ls -1(即数字1,而不是小写字母L)。
出什么问题了
ls > myfile.txt
这只会列出文件名(没有其他内容)并将它们发送到myfile.txt
如果要走awk路线,只需执行
ls -l | awk '{print $9}'
awk的默认操作是在空间上拆分字段-这将在每行打印第9个字段…
如果您想对文件名进行其他操作,则可以扩展awk脚本。例如,可以使用以下命令创建具有这些文件名的数组
ls -l | awk '{a[NR]=$9}'
您可以在进一步处理中使用此数组(称为a)。如果处理需要除awk之外的其他内容(我认为确实需要注释),那么看起来更好的东西会更好
#!/bin/bash
for f in $1"/"*
do
if [ -d"$f" ] ; then
./listdir $f
else
echo $f
fi
done
将此文件另存为listdir在当前目录中,一切顺利。
./listdir .
将列出整个目录,并根据需要向下递归(附加完整的相对路径)。
如果希望"从任何地方"都可以使用它(毕竟这是一个非常有用的命令),则可以将其放在路径中的某个位置(并执行" rehash"命令,以便它被"知道");则在命令开始时不需要./。
myfile.txt来自哪里?这不是问题。
,,但是我该如何一次遍历列表中的一项?
@richard-问题说"我需要存储"……我决定将其存储在文件中。
@matteo-您想如何迭代?我给出的awk行为每次迭代提供了一个值。您可以将其他表达式放在awk脚本中。
抱歉,您是对的。
对于目录中包含的所有文件(如果它是文件),我将不做任何事情;如果它是目录,则应将目录名附加到它包含的所有文件中。
太酷了!)