我有一个包含多个文件的目录,其中一些文件是 bash 脚本,但它们的名称不包含 .sh 扩展名。我知道我需要使用 file 命令来了解带有 -type 选项的文件类型,我也知道我可以使用 xargs 重定向输出,这样我就可以使用原始名称 + .sh 扩展名重命名文件。问题是我不知道如何将所有命令连接在一起,也不知道如何查找仅 bash ASCII 文本可执行文件的文件类型。知道如何用一个简单的命令来做到这一点吗?
答案1
如果您设置了任何标准 shebang 行,它看起来file
(至少版本 5.39)应该能够检测到它们:
$ echo '#!/usr/bin/env bash' > 1
$ echo '#!/bin/bash' > 2
$ echo '#!/usr/bin/bash' > 3
$ file *
1: Bourne-Again shell script, ASCII text executable
2: Bourne-Again shell script, ASCII text executable
3: Bourne-Again shell script, ASCII text executable
所以我们应该能够这样做:
for path in ./*
do
if [[ "$(file "$path")" = "${path}: Bourne-Again shell script, ASCII text executable" ]]
then
mv "$path" "${path}.bash"
fi
done
这适用于上面的示例文件(并且应该适用于不寻常的文件名,包括包含空格字符、以连字符开头或以换行符结尾的文件名):
$ ls
1.bash 2.bash 3.bash
这可能会不是如果您的文件没有 shebang 行(这对于以下文件是合理的),则可以工作由其他脚本获取或者 shebang 行是错误的(例如#!/bin/sh
)。
(我使用了“.bash”,因为它比“.sh”更明确。)
答案2
尽管这不能完成您的作业,但不需要find
as grep
kann 递归地搜索文件目录-r
(甚至当文件名通过通配符传递时也不需要)
grep -lIw '^#!.*bash' dir/!(*.sh) | xargs -I_ mv _ _.sh
grep-r
目录将搜索所有子目录中的所有文件(此处未使用)
grep-l
类似于-H
打印每个匹配的文件名,但抑制正常输出。此外,它在第一个匹配后停止,类似于-q
或-m1
grep-I
排除二进制文件,仅处理文本文件
grep-w
巴什仅匹配整个单词(不匹配巴什编辑)
正则表达式^
#!仅匹配行首(不匹配 ##!)
正则表达式.
匹配任何字节*
任何出现=.*
任何字符串
路径名扩展(通配符)*.sh
与模式 file.sh 匹配
扩展通配!(pattern)
匹配除模式之外的任何内容
lsdir/!(*.sh)
列出所有文件目录排除目录/文件.sh文件
参数-I
图案将在每个位置插入参数图案_
本例中使用:
mv _ _ .sh
mv file1 file1.sh
mv file2 file2.sh