Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/unix/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Unix sed脚本正在关闭其中一个文件_Unix_Sed - Fatal编程技术网

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?