ls -1
像这样列出我的元素:
foo.png
bar.png
foobar.png
...
我希望它没有.png
类似的列出:
foo
bar
foobar
...
(目录仅包含.png
文件)
有人可以告诉我grep
在这种情况下如何使用吗?
目的:我有一个文本文件,其中列出了所有名称而没有扩展名。我想制作一个脚本,将文本文件与文件夹进行比较,以查看缺少哪个文件。
ls -1
像这样列出我的元素:
foo.png
bar.png
foobar.png
...
我希望它没有.png
类似的列出:
foo
bar
foobar
...
(目录仅包含.png
文件)
有人可以告诉我grep
在这种情况下如何使用吗?
目的:我有一个文本文件,其中列出了所有名称而没有扩展名。我想制作一个脚本,将文本文件与文件夹进行比较,以查看缺少哪个文件。
Answers:
您只需要外壳即可完成这项工作。
POSIXly:
for f in *.png; do
printf '%s\n' "${f%.png}"
done
与zsh
:
print -rl -- *.png(:r)
printf
; echo ${f%.png}
就足够了。
ls -1 | sed -e 's/\.png$//'
该sed
命令删除(即用空字符串替换).png
在文件名末尾找到的所有字符串。
的.
作为被转义\.
,使得它被解释sed
为一个文字.
字符,而不是正则表达式.
(其装置匹配任何字符)。该$
是结束线的锚,所以它不匹配.png
文件名中的中间。
sed 's/\.[^.]*$//'
-1
是没有必要的,是这里的默认值。
-1
应该指定。这是管道打开时的唯一默认设置,这对于某些人来说是一个隐藏的惊喜。因此,将其明确表示有助于理解。我也在脚本中执行此操作,因此我知道期望什么样的输出。
.png
在换行符前带有键(),则您甚至会擦除该字符,.png
而不仅仅是最后一个。最好避免管道分析ls的输出,它通常会保留一些隐藏的惊喜……(答案中的某些单词和参考文献更多)。
如果您只想使用bash:
for i in *; do echo "${i%.png}"; done
grep
在尝试查找匹配项时,您应该伸出援手,而不是删除/替代,这sed
更合适:
find . -maxdepth 1 -name "*.png" | sed 's/\.png$//'
一旦确定需要创建一些子目录以使PNG文件中具有顺序,您可以轻松地将其更改为:
find . -name "*.png" | sed 's/\.png$//'
find
管道传递到sed
解决方案可能会出现一些问题.png
。最好避免管道传输或解析find
or 的输出ls
,它通常会保留一些隐藏的惊喜...(答案中的某些单词和参考文献更多)。
我会去basename
(假设GNU实现):
basename --suffix=.png -- *.png
-z
(或--zero
)选项产生NUL分隔(而不是换行分隔)的输出会有所帮助。
另一个非常相似的答案(我很惊讶这个特殊的变体还没有出现)是:
ls | sed -n 's/\.png$//p'
-1
选择ls
,因为它ls
假设标准输出不是终端(在这种情况下为管道)。-n
选项sed
的意思是“默认不打印线”/p
替换末尾的选项表示“ ...如果进行替换,则打印此行”。这样做的最终效果是只打印出以结尾的行.png
,并.png
删除它们。也就是说,这也满足了OP问题的一般化要求,即目录不只包含.png
文件。
sed -n
在您可能另外使用grep + sed的情况下,该技术通常很有用。
.png
在换行符char之前加一个键()会更讨厌,那就更不用说了:在这种情况下,您将打印不带png的那部分,而不会仅删除最后一部分。通常建议避免解析(和传递)输出,ls
因为问题可能隐藏在您未考虑的地方……
ls
,但是它正在解决未来的问题。当我们已经忘记了它们的局限性时,我们通常会制作一些脚本,供以后使用(这是很正常的,这是很人性的)。我提出了一个find
示例(有-exec
管和无管),即使我认为更好的(因为是纯壳)也可以回答cuonglm的一个,完全和posix兼容的问题。
locate
或make
。
您只能使用BASH命令来执行此操作(而无需任何外部工具)。
for file in *; do echo "${file%.*}"; done
当您没有/ usr / bin时,这非常有用,它对于像this.is.image.png这样的文件名以及所有扩展名都很好用。
ls
或管find
[ 1,2 ]解析(或管道传递)ls
or 的输出是不安全的find
,主要是因为可以在文件名中找到非常用字符作为换行符,制表符 ...在这里,将使用纯shell循环[ cuonglm ]。
即使未使用该选项传递find
命令的命令也可以使用:-exec
find ./*.png -exec basename {} .png \;
更新/注释:您find .
甚至可以搜索隐藏文件,或find ./*.png
仅获取未隐藏的文件。在find *.png -exec ...
存在一个名为的文件的情况下,您可能会遇到问题,.png
因为find会将其作为选项。您可以添加-maxdepth 0
以避免进入名为的目录Dir_01.png
,或者find ./*.png -prune -exec ...
在不允许maxdepth的情况下使用(感谢Stéphane)。如果要避免列出这些目录,则应添加选项-type f
(这还将排除其他类型的非常规文件)。让我们看一下man
有关所有可用选项的更完整的全景图,并记住检查它们是否符合POSIX,以获得更好的可移植性。
例如,可能会发生以下情况:从文档复制标题并粘贴到文件名中,一个或多个换行符将在文件名本身中结束。我们可能很不幸,标题甚至可以包含换行之前必须使用的键:
The new art of working on .png
files and other formats.
如果要测试,可以使用以下命令创建文件名
touch "A file with two lines"$'\n'"and This is the second.png"
touch "The new art of working on .png"$'\n'"files and other formats.png"
简单/bin/ls *png
将输出?
而不是不可打印的字符
A file with two lines?and This is the second.png
The new art of working on .png?files and other formats.png
在所有情况下,您都将通过管道传输的输出,ls
否则find
以下命令将没有提示来了解当前行是否来自新文件名,或者该行是否位于先前文件名中的换行符之后。一个讨厌的名字确实,但还是一个法律问题。
${parameter%word}
在带有printf
或的变体中,带有shell Parameter-Expansion的shell循环echo
将工作[ cuonglm ],[ Anthon1 ]。
for f in *.png; do printf "%s\n" "${f%.png}" ; done
在Shell参数扩展的手册页中[ 3 ]
$ {parameter%word}
$ {parameter %% word}...扩展的结果是删除了最短匹配模式(%情况)或最长匹配模式(%%情况)的参数值。
ls
当通过管道传输或重定向输出时,都没有问题,但是正如Wiki中所提到的,它可能不适用于所有人。?
当输出发送到终端时,大多数只会在特殊字符的位置插入。即做echo *.png | od -c
和ls *.png | od -c
。换行问题不是问题ls
,这是任何不为空的两端在管道两端终止的命令的问题。
printf "${f%.png}\n"
是错的。第一个参数是格式,您不应在其中使用变量数据。甚至可以看作是DoS漏洞(例如尝试使用%1000000000s.png
文件)。
find ./*.png -prune -exec...
或者你有开头的文件名的问题-
(和类型目录的文件,注意,-maxdepth
不可移植)
用途rev
:
ls -1 | rev | cut -f 2- -d "." | rev
rev
反转所有字符串(行);您在第一个'之后切掉了所有内容。和rev撤消剩余。
如果您想grep
“母校”:
ls -1 | rev | cut -f 2- -d "." | rev | grep 'alma'
-1
是没有必要的,是这里的默认值。
My.2016.Summer.Vacation.png
cut -f 2-
.png
和换行符的文件...建议避免解析,ls
因为它喜欢很好地隐藏惊喜... :-)
如果我知道该目录仅包含扩展名为.png的文件,则可以运行: ls | awk -F. '{print $1}'
这将为存在filename.extension的任何内容返回第一个“字段”。
例:
[rsingh@rule51 TESTDIR]$ ls
10.png 1.png 2.png 3.png 4.png 5.png 6.png 7.png 8.png 9.png
[rsingh@rule51 TESTDIR]$ ls | awk -F. '{print $1}'
10
1
2
3
4
5
6
7
8
9
.
在\.
里面的sed -e 's/\.png$//'
,但可以使其变成一个答案刚写。:-( note2您可以尝试使用awk
类似ls | awk -F. '{if ($NF=="png") {for (i=1;i<NF-1;i++) printf("%s.", $i) ; printf $(NF-1)"\n"}}'
...的方法,但是您将始终遇到awk无法知道行名是否在文件名后的换行符的问题。我试图在回答中说得更好。
根据您的评论“我有一个文本文件,其中列出了所有名称而没有扩展名。我想制作一个PHP脚本,将文本文件与文件夹进行比较,以查看缺少哪个文件”:
for file in $(cat yourlist) ; do
[ -f "${file}.png" ] || {
echo "$file : listed in yourlist, but missing in the directory"
}
done
#assumes that filenames have no space...
# otherwise use instead:
# while IFS= read file ; do ...(same inner loop as above)... ; done < yourlist
相反:
for file in *.png ; do
grep "^${file%.png}$" yourlist >/dev/null || {
echo "$file: present in the directory but not listed in yourlist"
}
done
#I assume there are no spaces/tabs/? before/after names in 'yourlist'. Change the script accordingly if there are some (or sanitize the list)
简单的外壳线(ksh,bash或zsh;不是破折号):
set -- *.png; printf '%s\n' "${@%.png}"
一个简单的功能(来自No Extension):
ne(){ set -- *.png; printf '%s\n' "${@%.png}"; }
或删除给定扩展名的函数(默认为png):
ne(){ ext=${1:-png}; set -- *."$ext"; printf '%s\n' "${@%.${ext}}"; }
用于:
ne jpg
如果输出为星号*
,则不存在具有该扩展名的文件。
如果您有sed的权限,这样做会更好,因为无论它是什么(png,jpg,tiff等),它都会删除最后一个文件扩展名。
ls | sed -e 's/\..*$//'
this.is.a.dotty.txt
。试试吧s/\.[^.]*$//
。
.
。尽管惯例说最后要用来命名文件.png
,但没有理由为什么我不能将png文件命名为foo.zip
ormy.picture.20160518
或justmypic
。