我需要存储带有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
更好的方法是使用bash globbing
只列出所有文件
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##*.}
假定扩展名是最后一个阶段之后的所有内容,因此,如果您在Directory 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"
中直接扩展到任何类型(常规,dir,symlink等)的每个文件
ls > myfile.txt
这只会列出文件名(没有其他)并将其发送到myfile.txt
如果您想走awk
路线,只需做
ls -l | awk '{print $9}'
awk
的默认操作是在空间上拆分字段 - 这将为每行的第9个字段打印…
如果您想用文件名做其他事情,则可以扩展尴尬脚本。例如,可以使用
创建带有这些文件名的数组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"命令,以便它将是"已知");然后,您不需要命令开始时的./
。
好问题!很高兴你问。解析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 ;
-
在鲍勃的主目录中删除jpegs(该死的鲍勃和你流浪的眼睛):
find ~bob/ -name '*.jpg' -delete
-
递归循环浏览文件,并向它们做复杂的事情:
find /dir/to/search -print0 | while read -d $' ' file; do echo "$file" touch "$file" if [[ -L $file ]]; then # $file is a symlink, do something special fi done
ls -l | awk '{split($0,array," ")} {print array[9]}'
或
ls -l | awk '{print $9}'
但是为什么不只是ls
?