【问题标题】:Linux: Pipe `find` text file list | `dos2unix` | `dd` commandLinux:管道`find` 文本文件列表| `dos2unix` | `dd` 命令
【发布时间】:2015-08-24 00:59:58
【问题描述】:

我正在尝试做的事情:

  • 第 1 行:查找任何 .txt 或 .TXT 文件并将它们通过管道传递到下一个命令
  • 第 2 行:将 .txt 文件转换为 unix 格式(去掉 Windows 行尾)
  • 第 3 行:删除文件的最后一行,始终为空
find "${TEMPDIR}" -name *.[Tt][Xx][Tt] | /
xargs dos2unix -k | /
dd if=/dev/null of="$_" bs=1 seek=$(echo $(stat --format=%s "$_" ) - $( tail -n1 "$_" | wc -c) | bc )

我无法将xargs dos2unix -k | / 的 (EDIT output) 文件名传送到第三行,我收到以下错误:

stat: cannot stat '': No such file or directory
tail: cannot open '' for reading: No such file or directory
dd: failed to open '': No such file or directory

显然我错误地认为"$_" 足以通过管道传递输出。

如何将xargs dos2unix -k 的输出(文本文件)通过管道传输到第三行dd if=/dev/null of="$_" bs=1 seek=$(echo $(stat --format=%s "$_" ) - $( tail -n1 "$_" | wc -c) | bc )

第 3 行的解决方案来自对 SO 上关于从文件中删除最后一行的另一个问题的回答,该回答特别被吹捧为大文件的良好解决方案:https://stackoverflow.com/a/17794626/893766

【问题讨论】:

  • dos2unix 程序不会产生任何输出,所以xargs dos2unix -k 也不会。它只是默默地转换文件。
  • 您也可以使用find -iname 进行不区分大小写的搜索
  • 只是不要管道它,它会在适当的位置编辑文件。请改用;,然后继续您的工作。
  • dd 命令需要在您尝试修改的文件上运行——您链接到的问题特别注意这一点。因此,它不能在管道末尾运行,因为没有要编辑的文件名。
  • 管道字符后的斜线是语法错误。您可能打算使用反斜杠,但在这里它们也不是必需的——shell 知道后面没有任何内容的管道是一个多行命令,它将在下一行继续。

标签: bash pipe ubuntu-14.04


【解决方案1】:

您可以尝试用显式替换替​​换dos2unix

find "${TEMPDIR}" -iname '*.txt' -exec cat {} \; |
tr -d '\r' |
...

由于换行的窗口是\r\n,您可以使用命令tr 删除所有出现的\r

关于find 命令,您可以使用选项-iname 进行不区分大小写的搜索,使用-exec 运行命令。

【讨论】:

  • 我不确定,但如果您遇到问题,您可以使用不同的命令。 perl 肯定可以处理代码页。看看这个页面cyberciti.biz/faq/…
【解决方案2】:

这有帮助吗?

find "${TEMPDIR}" -iname '*.txt' -exec dos2unix "{}" \; -exec sed -i '$d' "{}" \;

【讨论】:

  • 哇,我不知道你可以为find 提供多个-exec 参数。
  • 这很好,只要你把 {} 周围的引号去掉。 :)
  • ^^ 我不明白。在{} 周围加上引号是错误的,还是不必要的?我用一个简单的echo 作为命令进行了测试,它给出了预期的结果...find . -exec echo "#{}#" \;
  • @tripleee:我也不知道。早些时候,我将-exec-print0 结合起来用于管道内衬。所以我尝试了这个,它奏效了。
  • @tripleee:但是在{} 周围加上引号对文件名、引用或其他方式没有任何作用——它甚至不会到达find 进程。引号只是“保护”{} 到达find 进程 - 当然,不需要这样的保护,但也不会造成任何伤害:)
【解决方案3】:

如果文件真的很大,你已经用tr重写它来搞乱效率。然后,您使用tail 再次阅读它只是为了获取最后一行的索引。

我能想出的效率最低的解决方法是用一个同时执行这两个功能的命令替换 dos2unixdd,这样您只需读取和写入输出文件一次。

find "$TMPDIR" -iname '*.txt' -exec perl -i -ne '
    print $line if defined $line; ($line = $_) =~ s/\015$//' {} \;

您尝试使用$_ 作为当前文件名无效。 $_ 的值是上一个完成命令使用的最后一个文件名;但是在管道的中间,还没有完成任何事情。一种可能的解决方法(我只是为了说明,而不是作为推荐的解决方案)是在您可以访问{}xargs 中运行所有内容,类似于它在find -exec 中的工作方式。

find "$TMPDIR" -iname '*.txt' -print0 |
xargs -r0 sh -c 'dos2unix -k "{}"
    if=/dev/null of="{}" bs=1 seek=$(
        echo $(stat --format=%s "{}" ) - $( tail -n1 "{}" | wc -c) | bc)

我添加了-print0 和相应的xargs -0 以及xargs -r 作为良好形式的插图;虽然以零结尾的文本格式是 GNU find 扩展名,但在其他平台上通常找不到。

(私下里,我可能还会用一个简单的 Awk 脚本替换 seek 计算,而不是花费三个过程来执行减法。)

【讨论】:

  • 感谢您的额外信息
猜你喜欢
  • 2013-11-23
  • 2012-06-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-02
  • 1970-01-01
  • 2012-01-28
  • 2010-10-26
相关资源
最近更新 更多