有人知道为什么 bash 仍然默认启用历史替换吗?我的.bashrc已经包含set +H很多年了,但其他一些人仍然被这个功能所吸引。
鉴于几乎每个人都使用具有复制粘贴功能的终端,并且使用readline库编译的 bash和历史替换在默认情况下仅在交互式 shell 中启用,真的有任何理由拥有该功能吗?即使默认情况下为所有 shell 禁用此功能,也不会破坏现有脚本。
如果你不知道为什么历史替换被破坏,试试这个:
$ set +H # disable feature history substitution
$ echo "WTF???!?!!?"
WTF???!?!!?
$ set -H # enable feature history substitution
$ echo "WTF???!?!!?"
echo WTF???echo WTF???!?!!?
WTF???echo WTF???!?!!?
Run Code Online (Sandbox Code Playgroud)
(显然,如果默认情况下所有脚本都禁用该功能,并且存在一个功能可以在执行之前验证结果,则该功能存在重大问题:shopt -s histverify。)
也可以看看:
有没有办法告诉sed在每第二次出现时替换模式?或者至少每隔一行?(当然可以使用脚本,但我问自己是否sed可以做到)。
编辑
我发现
sed -e "s/pattern/replacement/g;n"
Run Code Online (Sandbox Code Playgroud)
但它取代了每一次出现,而不是第二次。
例子
输入文件:
I have a pattern in each line
Also the second line has the pattern
Another pattern here
And -- you guess it -- a pattern
Run Code Online (Sandbox Code Playgroud)
期望的输出:
I have a pattern in each line
Also the second line has the replacement
Another pattern here
And -- you guess it -- a replacement
Run Code Online (Sandbox Code Playgroud) 在对这个问题的评论中,出现了一个案例,其中各种 sed 实现在一个相当简单的程序上存在分歧,我们(或至少我)无法确定规范实际需要什么。
问题是从已删除行开始的范围的行为:
1d;1,2d
Run Code Online (Sandbox Code Playgroud)
即使在到达该命令之前删除了范围的开头,也应该删除第 2 行吗?我最初的期望是“否”,符合 BSD sed,而 GNU sed 说“是”,检查规范文本并不能完全解决问题。
符合我的期望的是(至少) macOS 和 Solaris sed,以及 BSD sed。不同意(至少)GNU 和 Busyboxsed以及这里的许多人。前两个是 SUS 认证的,而其他的可能更广泛。哪种行为是正确的?
两个地址范围的规范文本说:
然后sed实用程序应按顺序应用其地址选择该模式空间的所有命令,直到命令开始下一个循环或退出。
和
具有两个地址的编辑命令应选择从与第一个地址匹配的第一个模式空间到与第二个地址匹配的下一个模式空间的包含范围。[...] 从所选范围之后的第一行开始,sed 将再次查找第一个地址。此后,应重复该过程。
可以说,第2行是 内,不管开始点是否已删除“从通过相匹配的第二下一图案空间匹配的第一个地址中的第一图案空间包容范围”。另一方面,我期待第一个d进入下一个周期,而不是给这个范围一个开始的机会。UNIX™ 认证的实现符合我的预期,但可能不是规范要求的。
一些说明性的实验遵循,但关键的问题是:什么应该 sed在范围上已删除的行开始呢?
这个问题的一个简化演示是这样的,它打印额外的行副本而不是删除它们:
printf 'a\nb\n' | sed -e '1d;1,2p'
Run Code Online (Sandbox Code Playgroud)
这提供sed了两行输入,a和b。该程序做了两件事:
删除第一行1d。该d命令将
删除模式空间并开始下一个循环。和
脚本出于某种目的bash使用变量Q(超出了本问题的范围):
Q=0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ
Run Code Online (Sandbox Code Playgroud)
由于这个脚本是在每个字节都很重要的环境中使用的,所以这是浪费。但有些解决方法就像
Q=0$(seq -s "" 9)$(echo {A..Z}|tr -d " ")
Run Code Online (Sandbox Code Playgroud)
(对于C语言环境)更糟。我是不是太盲目了,看不到紧凑地生成如此简单序列的明显技巧?
为什么使用 of*(1)*会删除目录中的所有内容?那么如何选择(1)名称中间有的所有文件呢?
使用的命令是rm *(1)*or rm -rf *(1)*(记不太清了)。这是默认的 Ubuntu shell。
我在嵌入式设备上的 jessie 上,试图将 WLAN 设置为 AP 模式。当我尝试
# /usr/sbin/hostapd -P /run/hostapd.wlan0.pid /etc/hostapd/hostapd.conf
Configuration file: /etc/hostapd/hostapd.conf
ACS: Automatic channel selection started, this may take a bit
wlan0: interface state UNINITIALIZED->ACS
wlan0: ACS-STARTED
ACS: Unable to collect survey data
ACS: All study options have failed
Interface initialization failed
wlan0: interface state ACS->DISABLED
wlan0: AP-DISABLED
ACS: Possibly channel configuration is invalid, please report this along with your config file.
ACS: Failed to start
wlan0: AP-DISABLED
hostapd_free_hapd_data: Interface wlan0 wasn't started
wlan0: interface state …Run Code Online (Sandbox Code Playgroud) 我需要resize2fs嵌入式设备的根分区。由于它没有备用启动选项,我使用了一个tmpfs,移动并重述了所有内容,直到我最终能够umount /dev/mmcblk0p1. 但是运气不好:
$ umount /dev/mmcblk0p1
umount: /dev/mmcblk0p1: not mounted
$ resize2fs /dev/mmcblk0p1
resize2fs 1.42.12 (29-Aug-2014)
resize2fs: Device or resource busy while trying to open /dev/mmcblk0p1
Couldn't find valid filesystem superblock.
$ fsck /dev/mmcblk0p1
fsck from util-linux 2.25.2
e2fsck 1.42.12 (29-Aug-2014)
/dev/mmcblk0p1 is in use.
e2fsck: Cannot continue, aborting.
Run Code Online (Sandbox Code Playgroud)
奇怪的!一个繁忙的卸载文件系统。在我看来,该期刊仍然掌握着设备:
root 112 0.0 0.0 0 0 ? S 14:13 0:00 [jbd2/mmcblk0p1-]
Run Code Online (Sandbox Code Playgroud)
关掉日志,你说?鸡与蛋的游戏来了:
$ tune2fs -O ^has_journal /dev/mmcblk0p1
tune2fs 1.42.12 (29-Aug-2014)
The needs_recovery flag is …Run Code Online (Sandbox Code Playgroud) 我刚刚发现如果我执行
echo foo|sed 's/x/u/w/tmp/bar'
Run Code Online (Sandbox Code Playgroud)
使用 GNU 时sed,会创建一个空文件/tmp/bar,这不是有意的,因为该w标志不适用。更糟糕,
echo foo|sed 'd;w/tmp/bar'
Run Code Online (Sandbox Code Playgroud)
还创建了那个空文件!呜呜。
事实上,GNUsed手册也承认:
该文件将在读取第一个输入行之前创建(或截断)
我想,如果您不必测试每个文件句柄是否打开,那么实现起来会更容易,但是 的 POSIX 定义并sed没有说可以在不执行命令的情况下触摸该文件。--posixGNU 的切换没有sed帮助。
sed您知道这种情况下其他实现的行为吗?
或者我误解了这里的标准?
Kali Linux Rolling 使用哪个版本的 Debian?
root@TRax:~# uname -a
Linux TRax 4.9.0-kali3-amd64 #1 SMP Debian 4.9.13-1kali3 (2017-03-13) x86_64 GNU/Linux
root@TRax:~# lsb_release --codename
Codename: kali-rolling
Run Code Online (Sandbox Code Playgroud) 今天在另外两个问题中偶然发现这个现象后,我仔细研究了这个现象。我已经在默认情况下尝试了所有这些set -H(历史扩展打开)。
为了测试脚本,我经常做一些事情,例如echoing 多行字符串并将其通过脚本进行管道传输,但在某些情况下会出现错误:
$ echo "foo
bar" | sed '/foo/!d'
bash: !d': event not found
>
Run Code Online (Sandbox Code Playgroud)
!尽管用单引号括起来,但似乎会触发历史扩展。问题似乎是在同一行中出现双引号,因为
$echo $'foo\nbar' | sed '/foo/!d'
Run Code Online (Sandbox Code Playgroud)
效果也很好
$echo "foo
bar" |
> sed '/foo/!d'
Run Code Online (Sandbox Code Playgroud)
我的怀疑:历史扩展是按行应用的,所以'后面的单个"被认为是转义的,所以下面的!没有转义。
现在我的问题是:这是一个错误还是预期的行为?复制bash版本为 4.2.30 和 4.4.12。
bash ×4
debian ×3
sed ×3
posix ×2
access-point ×1
ext4 ×1
filenames ×1
hostapd ×1
journaling ×1
kali-linux ×1
quoting ×1
replace ×1
resize2fs ×1
shell-script ×1
version ×1
wildcards ×1
wlan ×1