Unix sed脚本正在关闭其中一个文件
我在尝试使此脚本正常工作时遇到问题。特别是在一个地方。脚本如下:Unix sed脚本正在关闭其中一个文件,unix,sed,Unix,Sed,我在尝试使此脚本正常工作时遇到问题。特别是在一个地方。脚本如下: egrep -v "total" asg4edb > /class/cm325d/06/dASG4/t1 egrep ":" t1 > /class/cm325d/06/dASG4/t2 sed 's/^-/r/' t2 > t1 sed 's/cm325d06/me/' t1 > t2 sed 's/cm325d/gang/' t2 > t1 sed 's/^d/A/' t1 > t2 sed
egrep -v "total" asg4edb > /class/cm325d/06/dASG4/t1
egrep ":" t1 > /class/cm325d/06/dASG4/t2
sed 's/^-/r/' t2 > t1
sed 's/cm325d06/me/' t1 > t2
sed 's/cm325d/gang/' t2 > t1
sed 's/^d/A/' t1 > t2
sed 's/^\./Z/' t2 > t1
egrep '^Z' t1 > subdirs
egrep '^r|^A' t1 > /class/cm325d/06/dASG4/files4
sed 's/rwx/7/;s/rw-/6/;s/r-x/5/;s/r--/4/;s/-wx/3/;s/-w-/2/;s/--x/1/;s/---/0/' /class/cm325d/06/dASG4/files4 > /class/cm325d/06/dASG4/files4
echo -e "cm325d06 \t Gilman \t Randy" > /class/cm325d/06/dASG4/asg4edf
( echo " " ; echo " " ) >> /class/cm325d/06/dASG4/asg4edf
cat /class/cm325d/06/dASG4/subdirs >> /class/cm325d/06/dASG4/asg4edf
( echo " " ; echo " " ) >> /class/cm325d/06/dASG4/asg4edf
cat /class/cm325d/06/dASG4/files4 >> /class/cm325d/06/dASG4/asg4edf
rm /class/cm325d/06/dASG4/t1 /class/cm325d/06/dASG4/t2 /class/cm325d/06/dASG4/subdirs
当我试图打开files4文件时,它是空的
此命令:
sed 's/rwx/7/;s/rw-/6/;s/r-x/5/;s/r--/4/;s/-wx/3/;s/-w-/2/;s/--x/1/;s/---/0/' /class/cm325d/06/dASG4/files4 > /class/cm325d/06/dASG4/files4
这没有意义,因为当我向它添加“>>”时,它只会将数据添加到文件的其余部分。但是,我需要它来覆盖旧数据。我真的很困惑为什么这不起作用。任何帮助都将不胜感激。问题不在于sed,而是shell处理重定向的方式。在命令
foo>bar
中,在执行foo
之前创建/截断文件栏。您可以看到这种情况发生,例如,使用
# make sure somefile is not an important file!
tac somefile > somefile
…这将给您留下一个空文件。(我本来会使用cat
,但是bash
会识别这种特殊情况并给出警告)。因为你的命令基本上是
sed 'some code' filename > filename
这发生在你身上。如果要使用sed
就地编辑文件,请使用其-i
选项:
sed -i 's/foo/bar/;s/baz/qux/' filename
请注意,可能在*BSD或MacOS X上使用的BSD sed要求-i
具有扩展参数,例如
sed -i.bak 's/foo/bar/;s/baz/qux/' filename
这将在filename.bak
中放置原始文件的备份。您也可以使用GNU sed(在Linux上可能会使用GNU sed)来实现这一点,如果您不想使用BSD sed进行备份,您可以使用-i'
请注意,在没有备份的情况下就地编辑文件是不安全的,因为如果您的计算机在错误的时间(例如)崩溃,您可能最终既没有原始文件,也没有转换的结果。我更喜欢使用
sed -i.bak 's/foo/bar/;s/baz/qux/' filename && rm filename.bak
因此,只有当sed
报告成功时,才会删除备份。核心问题
他的医生已经准确地诊断出了根本问题。该行:
sed 's/rwx/7/;s/rw-/6/;s/r-x/5/;s/r--/4/;s/-wx/3/;s/-w-/2/;s/--x/1/;s/---/0/' \
/class/cm325d/06/dASG4/files4 > /class/cm325d/06/dASG4/files4
关闭文件/class/cm325d/06/dASG4/files4
但还有更多…
整个剧本都在要求重写。当前目录似乎是/class/cm325d/06/dASG4/
(否则,脚本第二行中引用的t1
不是在第一行中创建的文件,第三行引用的t2
不是第二行中创建的文件)。这使我们能够从根本上简化脚本
起初的
当前目录
我想知道files4
是否也应该被删除。输入为asg4edb
;输出为asg4edf
和files4
合并命令
现在,我们可以查看不同的命令组。初始的egrep
和sed
命令只需使用sed
即可在一次操作中完成:
sed -e '/total/d' \
-e '/:/!d' \
-e 's/^-/r/' \
-e 's/cm325d06/me/' \
-e 's/cm325d/gang/' \
-e 's/^d/A/' \
-e 's/^\./Z/' \
asg4edb > t1
每个-e
选项都对应于一个完整的命令,并按顺序保存。事实上,即使是将信息写入subdirs
和files4
的下两个egrep
操作,也可以在相同的sed
脚本中进行管理:
sed -e '/total/d' \
-e '/:/!d' \
-e 's/^-/r/' \
-e 's/cm325d06/me/' \
-e 's/cm325d/gang/' \
-e 's/^d/A/' \
-e 's/^\./Z/' \
-e '/^Z/w subdirs \
-e '/^[rA]/w files4 \
-n asg4edb
-n
选项反映了我们不再需要标准输出的事实
还有权限映射
实际上,我们还可以在这个sed
脚本中执行权限映射sed
操作。权限映射仅适用于常规文件(r
)或目录(A
),而不适用于其他文件类型(Z
)。它还做一些特殊的事情,比如:
rwxr-x--x --> 751 # Perfectly OK
r-xr-x--x --> 5r-x1 # Really?
rw-r--r-- --> 64r-- # Really?
r--r--r-- --> 4r--r-- # Really?
每次替换都应该有一个g
修饰符
sed -e '/total/d' \
-e '/:/!d' \
-e 's/^-/r/' \
-e 's/cm325d06/me/' \
-e 's/cm325d/gang/' \
-e 's/^d/A/' \
-e 's/^\./Z/' \
-e '/^[rA]/{
s/rwx/7/g
s/rw-/6/g
s/r-x/5/g
s/r--/4/g
s/-wx/3/g
s/-w-/2/g
s/--x/1/g
s/---/0/g
w files4
}' \
-e '/^Z/w subdirs \
-n asg4edb
条件块强调原始脚本中前缀为Z
的行不会发生权限映射
重新组装
最后的步骤是将files4
和其他各种数据重新组合到输出文件asg4edf
中。我们可以通过一个重定向操作来实现这一点:
{
echo -e "cm325d06 \t Gilman \t Randy"
echo " "
echo " "
cat subdirs
echo " "
echo " "
cat /class/cm325d/06/dASG4/files4
} > asg4edf
我对选项卡周围的空格和包含单个空格的行有点怀疑。我想你最好是:
{
printf "cm325d06\tGilman\tRandy\n\n"
cat subdirs
printf "\n\n"
cat /class/cm325d/06/dASG4/files4
} > asg4edf
最终版本
不,它还不完美
请注意,仍然有一些可以(也可以说应该)改进的地方。例如:
- 脚本可能会有陷阱中断等,并在退出之前删除中间文件,因此它会将内容保留在找到它们时的状态
- 它也可以在生成最终输出文件时忽略中断。不过,这可能是本练习的一部分
- 中间文件名(
和subdirs
)也可以使用files4
命令生成mktemp
- 脚本可以将输入和输出文件名作为参数
file=/class/cm325d/06/dASG4/asg4edf
并使用$file
。长名字的重复在结尾几乎没有区别,这使得你很难阅读你的脚本。你需要后退一步,重新评估你在哪些问题上使用了哪些工具。shell只是一个调用工具的环境。grep是一种在文件中查找regexp并打印匹配行的工具。sed是一种在单行上进行简单替换的工具。如果您需要做这些事情中的任何一件或另一件,那么您应该使用awk,一种用于一般文本操作的工具。获取阿诺德·罗宾斯的《有效的Awk编程》一书。哇,这本书非常好,让它看起来更干净。非常感谢您提供的示例。很抱歉,我的代码看起来太糟糕了,我已经是第四周的UNIX入门了,所以我还在学习。此外,感谢在替换中使用g选项修复了我遇到的另一个问题。你真的知道你在做什么。再次感谢您,我的脚本现在符合所有标准。
{
echo -e "cm325d06 \t Gilman \t Randy"
echo " "
echo " "
cat subdirs
echo " "
echo " "
cat /class/cm325d/06/dASG4/files4
} > asg4edf
{
printf "cm325d06\tGilman\tRandy\n\n"
cat subdirs
printf "\n\n"
cat /class/cm325d/06/dASG4/files4
} > asg4edf
cd /class/cm325d/06/dASG4 || exit 1 # Optional
sed -e '/total/d' \
-e '/:/!d' \
-e 's/^-/r/' \
-e 's/cm325d06/me/' \
-e 's/cm325d/gang/' \
-e 's/^d/A/' \
-e 's/^\./Z/' \
-e '/^[rA]/{
s/rwx/7/g
s/rw-/6/g
s/r-x/5/g
s/r--/4/g
s/-wx/3/g
s/-w-/2/g
s/--x/1/g
s/---/0/g
w files4
}' \
-e '/^Z/w subdirs \
-n asg4edb
{
printf "cm325d06\tGilman\tRandy\n\n"
cat subdirs
printf "\n\n"
cat /class/cm325d/06/dASG4/files4
} > asg4edf
rm subdirs # files4 too?