linux shell ls -l,关于linux:用bash脚本解析`ls -l`的结果

本问题已经有最佳答案,请猛点这里访问。

我需要使用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脚本中。

抱歉,您是对的。

对于目录中包含的所有文件(如果它是文件),我将不做任何事情;如果它是目录,则应将目录名附加到它包含的所有文件中。

太酷了!)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值