我想找到当前目录中的所有文件,在处理其内容之前按字母顺序对它们进行排序,以提取每个文件中的前 3 个字符。这样做将创建一个句子,然后我可以将其重定向到另一个文件中。我尝试过这个:
find . -type f -exec basename {} \; | sort | xargs head -c 3
但我得到:
head:无法打开“filenamehere”进行读取:没有这样的文件或目录
对于我尝试提取前 3 个字符的每个文件。我能够做到这一点,但没有先对其进行排序。
答案1
编辑: 第一名:
find -type f -exec grep -I -q . {} \; -exec sh -c 'echo -e "$(basename "$0") {}"' {} \; | sort | cut -d ' ' -f2 | xargs sed -Ee 's/(^.{3})(.*)/\1/g'
grep -I -q . {} \;
将仅找到所有文本文件,而不是图像等二进制文件。
第二:
我的基本想法是创建一个哈希函数,其键等于基本名称,其值等于前 3 个字符。
#!/bin/bash
touch file_s
echo 'declare -A map' > file_s
find . ! -name file_s ! -name sort_map -type f -exec grep -I -q . {} \; \
-exec sh -c 'i="$(basename "$0")";echo "map["$i"]=$(head -n 1 "$0"|cut -c
1-3)" >> file_s;' {} \; | sort | while read -r line
do
source file_s
echo -e ${map["$line"]}
done
您应该在其中编写此代码的脚本的名称是sort_map
并且file_s
是临时的。文件。所以你不应该在 find 命令中包含这两个文件。grep -I -q . {} \;
将 grep 文件仅是文本文件,而不是二进制文件。
第二条-exec
命令如下:
i="$(basename "$0")";
将获取基本名称并写入变量 i。
echo "map["$i"]=$(head -n 1 "$0"|cut -c 1-3)" >> file_s;
将写入哈希函数及其值到临时文件file_s
。
sort
将对文件名进行排序。
while read -r line
do
source file_s
echo -e ${map["$line"]}
done
将逐行读取并获取文件file_s
。然后将打印前 3 个字符。
您不能使用 head,因为 head 打印文件的内容而不是文件名。
您可以使用:
find . -type f -exec basename {} \; | sort | cut -c 1-3
或者你也可以使用b
option 代替,c
但它会假设所有字符都是 1 个字节。
find . -type f -exec basename {} \; | sort | cut -b 1-3
它将获得前三个字符。
您可以使用:
find . -type f -exec basename {} \; | sort | sed -Ee 's/(^.{3})(.*)/\1/g'
它将对文件进行排序,然后匹配起始三个字符并仅打印它们。
笔记:所有这些命令都将空格和制表符视为一个字符。
答案2
不要basename
对 中的每个文件都运行find
,为找到的每个文件启动 shell 是对资源的巨大浪费。
find
(假设是 GNU 版本,尽管其他find
版本也可能支持这一点)有一个指令-printf
,它采用一个格式字符串,告诉它如何输出有关文件的信息,包括大小、所有权、权限等;不仅仅是它的名字。
其中一种格式是%f
删除所有前导目录的文件名,即您正在使用basename
的格式。所以你可以使用
find -type f -printf '%f\n'
您需要添加换行符\n
,以便每个文件名各占一行。
对您有利的另一个细节是您可以通过这种方式添加对要打印的字符数的限制。如果您希望打印最多 3 个字符的文件名,请使用:
find -type f -printf '%.3f\n'
现在只需添加sort
到混合中:
find -type f -printf '%.3f\n' | sort
你有你的解决方案。
编辑:因为看起来文件需要排序,然后需要输出其内容的前 3 个字符,所以命令变为:
find -type f -printf '%f\t%p\n' | sort | cut -f2 | xargs head -n 1 | cut -c1-3
这使用格式字符串首先仅显示基本文件名,然后是制表符,最后是完整路径。这可用于轻松对文件名进行排序。
cut -f2
仅提取选项卡后面的部分。
xargs head -n 1
获取每个文件的第一行。
cut -c1-3
显示每行的前三个字符。
该head -n 1
部分在管道中是必需的,否则cut
将显示每个文件每行的前 3 个字符。
答案3
使用 GNU head (for -q
) 和 shell 的默认通配符扩展排序:
head -q -c 3 * > /tmp/output
或者,
for file in *; do dd status=none if="$file" bs=1 count=3; done > /tmp/output
如果您的文件位于单个子目录中(根据你的单独评论),然后只需调整通配符:
head -q -c 3 /directory/subdirectory/* > /tmp/output
和
for file in /directory/subdirectory/* # ...
答案4
所以我终于在答案的启发下用我自己的解决方案解决了这个问题。我必须用 3 个命令而不是 1 个命令来完成它。我这样做了:
mkdir holder
find . -type f -exec mv -t holder {} \;
head -qc 3 ./holder/* > prophetie.txt
这使得整个句子按照需要从左到右排列。当我
ls -l holder
它们都是按字母顺序排列的,这样做时甚至不需要对它们进行排序..我猜是 mv 命令做到了?