我有一个文件(模式文件),我想通过 提供给 grep -f
,并且我想在另一个文件(搜索文件)中查找匹配项,其中字符串以给定模式开头。例如:
模式文件
1234
qwerty
chicken
搜索文件
12345
543212345
qwerty
1fwf32sgww
chicken fingers
鉴于上述文件,grep 应返回以下行
12345
qwerty
chicken fingers
我该怎么做?
我有一个文件(模式文件),我想通过 提供给 grep -f
,并且我想在另一个文件(搜索文件)中查找匹配项,其中字符串以给定模式开头。例如:
模式文件
1234
qwerty
chicken
搜索文件
12345
543212345
qwerty
1fwf32sgww
chicken fingers
鉴于上述文件,grep 应返回以下行
12345
qwerty
chicken fingers
我该怎么做?
我发现 perl 的opendir()
函数有一个奇怪的问题,对我来说绝对是零意义。
在以下示例中 perl 将打开 $path 指定的目录并提取所有子目录名称:
opendir(my $dh, $path) or die "can't opendir $path: $!";
my @dirs = grep { ! /^[\.]{1,2}$/ && -d "$path/$_" } readdir($dh);
closedir($dh);
foreach my $d (@dirs) {
print $encoder->encode($d);
}
在本例中,perl 将打开 $path 指定的目录并提取所有文件名:
opendir(my $dh, $path) or die "can't opendir $path: $!";
my @files = grep { ! /^[\.]{1,2}$/ && -f "$path/$_" } readdir($dh);
closedir($dh);
foreach my $f (@files) {
print $encoder->encode($f);
}
但是,我发现以下代码仅打印目录:
opendir(my $dh, $path) or die "can't opendir $path: $!";
my @dirs = grep { ! /^[\.]{1,2}$/ && -d "$path/$_" } readdir($dh);
my @files = grep { ! /^[\.]{1,2}$/ && -f "$path/$_" } readdir($dh);
closedir($dh);
foreach my $f (@files) {
print $encoder->encode($f);
}
foreach my $d (@dirs) {
print $encoder->encode($d);
}
grep
当在上面的例子中切换两行时,perl@files
首先分配,perl 将只打印文件。
怎么回事?!
我找到了一种解决方法,可以使用以下代码打印文件和目录:
opendir(my $dh, $path) or die "can't opendir $path: $!";
my @dirs = grep { ! /^[\.]{1,2}$/ && -d "$path/$_" } readdir($dh);
closedir($dh);
opendir(my $dh, $path) or die "can't opendir $path: $!";
my @files = grep { ! /^[\.]{1,2}$/ && -f "$path/$_" } readdir($dh);
closedir($dh);
foreach my $f (@files) {
print $encoder->encode($f);
}
foreach my $d (@dirs) {
print $encoder->encode($d);
}
但是,虽然我可以让我的脚本工作,但我仍然不知道为什么perl 会以它在这里的方式运行。据我了解,opendir()
打开一个目录并为第一个参数分配一个句柄,该参数由closedir()
. $dh
那么,如果是这种情况,如果句柄从未关闭,为什么我不能执行多项操作?
额外信息:
$ perl --version
This is perl 5, version 26, subversion 1 (v5.26.1) built for x86_64-linux-gnu-thread-multi
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 18.04.4 LTS
Release: 18.04
Codename: bionic
我在适用于 Windows 的 Linux 子系统上运行此代码
我想在 bash 中创建一个交互式 CLI。类似于 bash 为每一行添加前缀的方式user@host:~$
,我想在每一行添加前缀foobar>
。此功能可以在 Metasploit 或 mysqli 等 CLI 应用程序中看到,但它们使用单独的编程语言,而我想简单地使用 bash 脚本。此外,我需要向上/向下箭头键来使用该history
功能(或类似功能),允许用户轻松调出最后一个输入或之前的第 n 个输入。
在尝试创建解决方案时,我遇到了这个答案,它允许 bash 解释箭头键并使用history
. 这很好用,但是我很难将它与行前缀结合起来。我在这里找到了一个使用 coproc 预处理标准输出的解决方案并实现了一个版本,但是,这种方法既不适用于您正在输入的输入行,也不适用于使用带有history
. 我到目前为止的 bash 脚本如下:
exec 4>&1
coproc out (sed 's/^/foobar> /' >&4)
exec 1>&${out[1]}
printf "foobar> " >&4
while read -e x; do
history -s "$x"
echo $x
done
这是详细说明这两个问题的输出。正如您在下面看到的,我可以通过printf "foobar> " >&4
在 while 循环之前在上面的脚本中使用来为 cli 的第一行添加前缀。下面我boop
在第一行输入,echo 的输出被重定向到我的 coproc。但是在此之后,使用向上箭头将输入boop
带回将打印boop
没有我的前缀(如最后一行所示)。
$ ./test.sh
foobar> boop
foobar> boop
boop
我确实意识到,因为我在循环中没有 printf,所以我正在输入的行在第一次迭代后不会加前缀。稍后我可以通过重做循环来解决这个问题(尽管我担心将前缀行发送到前缀 coproc,因此需要双前缀)。我主要需要解决的是向上箭头输出没有加前缀。我假设这些信息是通过 发送的stdout
,但显然不是。我也尝试过stderr
以相同的方式重定向,但这会阻止终端在我输入时回显我输入的内容。
我需要一个解决方案来为 bash 脚本中的每一行添加前缀,无论它是基于我上面提供的脚本构建还是使用不同的方法。我还希望它尽可能优雅,因为我将使用这种技术构建一个 CLI 工具,并且希望尽可能少的额外开销。我认为重定向会为我做到这一点,但显然它比我最初想象的要复杂。