我有几个目录,每个目录都包含一个包含以下行的文件:
../a_a_q1.out ../a_a_q2.out ../a_a_q3.out
我想循环遍历所有子目录,并将该a_a
部分更改为当前子目录名称。例如,如果一个子目录被调用awesome_directory
,我希望这一行读取:
../awesome_directory_q1.out ../awesome_directory_q2.out ../awesome_directory_q3.out
我将如何实现这一目标?
我只想使用子目录名称。例如,我只需要 ( awesome_directory
) 部分而不是完整交易 ( //something/server/user/other_stuff/more/awesome_directory
)
答案1
在 bash 中分两步,这是一种方法 -
epwd=$(basename `pwd`)
sed -i "s/a_a/$epwd/g" <filename>
该变量$epwd
包含一个转义的目录名称,可用于 sed。 sed 命令将所有出现的 a_a 替换为工作目录
编辑:原始答案的第一行已被编辑为仅包含当前目录名称,而不是完整路径。如果你想要完整路径使用
epwd=$(pwd|sed 's/\//\\\//g')
答案2
到目前为止我想出了这个。
var=("${PWD##*/}")
sed -i "s/a_a/$var/g" filename
答案3
set '%s_q1.out %s_q2.out %s_q3.out\n'
:|for d in several directories
do cd -P -- "$d" || ! break
set "$1" "../${PWD##*/}"
{ sed -ne'\|\( \.\./a_a_q[123]\.out\)\{3\}|q;s/.//p'
printf "$@" "$2" "$2"; cut -c2-
} <<-IN >./infile
$(paste -d\ - ./infile)
IN
done
这应该可以与 POSIXsed
和bash
、zsh
、ksh
、mksh
shell 等一起使用。使用dash
或yash
shell 时,此处文档不太可能得到常规文件的支持,因此您不能依赖lseek()
支持共享输入所需的功能。在这些情况下,您应该切换到上述 shell 之一。
如果您使用 GNU,sed
您会希望使用sed -une
而不是仅仅使用sed -ne
。
这是一个细分:
首先我们
set
有一个参数,我们将printf
一遍又一遍地使用 as 的格式字符串,并将$PWD
和设置$OLDPWD
为.
接下来我们开始迭代中的项目
several directories
。无论这些是实际的目录还是符号链接,我们都会获得-P
物理的、规范的路径名,$PWD
并且set
它是$2
.接下来发生的事情发生在heredoc重定向的底部。
paste
将所有内容读取./infile
到 shell 为我们保护的某个安全临时文件中,同时在每一行前面添加一个空格。然后 shell 将该临时文件设置为 stdin 并./infile
再次分配 - 但这次作为 stdout。sed
很少进行编辑。在遇到匹配行之前,它会删除每行的第一个字符并p
打印结果。一旦它遇到你的行,它q
就会完全输入 - 不打印任何内容。但
printf
打印../${PWD##*/}_q[123].out
后跟一个换行符到标准输出,然后在离开的cut
地方拾取标准输入sed
(就在你的比赛线之后)并读出其余部分,同时从每个输入行中剥离第一个字节。
因此,整个编辑后的内容./infile
最终会回到原来的位置。
哦,我确实测试过。
我更换了several directories
对路径名进行了一些修改/tmp
,然后...
{ seq 7
echo '../a_a_q1.out ../a_a_q2.out ../a_a_q3.out'
seq 9 14
printf %s\\n '' '' ''
} >/tmp/infile
...写出了一个/tmp/infile
看起来像:
1 2 3 4 5 6 7 ../a_a_q1.out ../a_a_q2.out ../a_a_q3.out 9 10 11 12 13 14
不过,在运行上面的代码片段后/tmp
...
cat /tmp/infile
1 2 3 4 5 6 7 ../tmp_q1.out ../tmp_q2.out ../tmp_q3.out 9 10 11 12 13 14
答案4
如果该a_a
部分是恒定的并且您运行的是 Linux,那么您可以使用该rename
实用程序。在 Debian 及其衍生版本上,请更改rename
为,rename.ul
因为该rename
命令是一个不同的实用程序,它也可以完成此工作,但具有不同的语法。
使用循环遍历目录:
for d in */; do … done
调用rename
重命名每个目录中的文件。
for d in */; do
rename /a_a "/${d%/}" "$d"a_a*
done