我刚开始学习Bash脚本和编程。我想自动删除目录中多个.data文件的第一行。我的脚本如下:
#!/bin/bash
for f in *.data ;
do tail -n +2 $f | echo "processing $f";
done
我收到了回应信息,但是当我查看文件时内容没有改变。有什么想法吗?
提前致谢。
我刚开始学习Bash脚本和编程。我想自动删除目录中多个.data文件的第一行。我的脚本如下:
#!/bin/bash
for f in *.data ;
do tail -n +2 $f | echo "processing $f";
done
我收到了回显消息,但是当我查看文件时,文件内容并没有改变。
因为简单的使用tail
命令并不能改变文件内容。
你可以使用sed
命令来在原地修改文件,同时排除第一行。具体来说,可以这样做:
sed -i '1d' *.data
将从所有.data
文件中删除第一行。
注:BSD sed
(在OSX上)需要一个参数来使用-i
,因此您可以指定一个扩展名以备份旧文件,或者直接编辑文件:
sed -i '' '1d' *.data
tail
命令,你只是读取文件并将其部分内容输出到 stdout
(终端),你需要将该输出重定向到一个临时文件中,然后用临时文件覆盖原始文件。#!/usr/bin/env bash
for f in *.data; do
tail -n +2 "$f" > "${f}".tmp && mv "${f}".tmp "$f"
echo "Processing $f"
done
echo
命令的目的并不清楚。为什么在那里使用管道符(|
)? sed将为您提供更简单的实现方式。请参阅devnull的答案。#!/usr/bin/env bash
set -eu
for f in *.data; do
echo "processing $f"
tail -n +2 "$f" | sponge "$f"
done
如果您没有sponge
,可以在moreutils
软件包中获取它。
文件名周围的引号很重要 - 它们将使其适用于包含空格的文件名。而顶部的env
是为了让人们通过他们的PATH设置想要使用的Bash解释器,以防有人有非默认的解释器。set -eu
会使Bash在发生错误时退出,这通常更安全。
ed
是标准编辑器:
shopt -s nullglob
for f in *.data; do
echo "Processing file \`$f'"
ed -s -- "$f" < <( printf '%s\n' "1d" "wq" )
done
shopt -s nullglob
在这里是因为在使用通配符时你应该总是使用它,特别是在脚本中:如果没有匹配项,它将使通配符扩展为无内容;你不希望用不受控制的参数运行命令。
接下来,我们循环遍历所有文件,并使用以下命令:ed
1
:到第一行d
:删除该行wq
:写入并退出ed
的选项:
-s
:告诉ed
保持安静!我们不想让ed
在屏幕上打印垃圾信息。--
:选项结束:这将使你的脚本更加健壮,以防文件名以连字符开头:在这种情况下,连字符会混淆ed
试图处理它作为一个选项。使用--
,ed
知道在此之后没有更多选项,并将愉快地处理任何文件,即使文件名以连字符开头。
sed
的问题吗? - Markosed
上工作(这个版本在 OSX 上可用)。sed -i '1d' filename
是什么意思(其中filename
指的是单个文件)? - devnullsed
),sed
命令需要将扩展名作为-i
参数的一部分。你可以这样写:sed -i '' '1d' *.data
。我也已经编辑了答案。 - devnull