我正在使用 emacs,我希望可以运行一个命令,通过该窗口的工作目录来选择窗口,如果没有这样的窗口 - 则创建一个。我可以通过该命令创建 tmux 窗口
tmux new-window -c some_directory
但是我找不到如何按目录选择窗口,有这样的命令吗?或者,也许应该以不同的方式完成,在循环中运行验证,比较密码和目录?
答案1
我希望我可以运行一个命令,通过该窗口的工作目录来选择窗口,[…]。我可以通过该命令创建 tmux 窗口:
tmux new-window -c some_directory
该命令创建一个包含单个窗格的窗口。在 tmux 中,有pane_current_path
一种格式可以打印窗格的当前工作目录(如果可能)。针对某个窗口,该格式将打印窗口中活动窗格的当前工作目录。这实际上会忽略非活动窗格。如果每个窗口都有一个窗格,则每个窗格在其各自的窗口中都是活动的。否则至少有一个非活动窗格。
注意:man 1 tmux
在我的 Debian 中,术语“非活动窗格”通常用于表示不活动的窗格;这是我在此处使用的含义。但手册中很少使用“非活动窗格”,而它应该是“死窗格”;这不是我在此处使用的含义。
我不确定您是否想忽略非活动窗格。如果一个窗口中有多个窗格,则很容易忘记在选择另一个窗口时将一个特殊窗格设为活动窗格。在我的工作流程中,我从不关心离开窗口时哪个窗格处于活动状态。因此,我假设您想选择一个窗格通过该窗格的工作目录。
_tmux-find-cwd
我在指向的目录中的名称下有以下脚本PATH
。
#!/bin/sh
if [ "$#" -ne 1 ]; then
printf '%s\n' "exactly 1 argument needed" >&2
exit 1
fi
if [ "$CD_TO_PANE" ]; then
cd "$(tmux display -p '#{pane_current_path}')"
fi
tpth="$(realpath -e "$1//")" || exit 1
tmux list-panes -s -F '#{window_id} #{pane_id} #{pane_current_path}' \
| while IFS=' ' read -r wndw pne pth; do
[ "$pth" = "$tpth" ] && tmux select-pane -t "$pne" && tmux select-window -t "$wndw" && exit 0
done || tmux new-window -c "$tpth"
在 shell 中我像这样使用它:
_tmux-find-cwd some_directory
脚本会尝试查找具有匹配工作目录的窗格。将选择第一个匹配项,不再测试其他窗格。如果没有匹配项,则会按照您的要求创建一个窗口。
通常,脚本不会更改其工作目录,因此some_directory
相对路径也可以工作。当涉及符号链接时,您可能会得到意外结果,请参阅这。
然后我的里面有这一行~/.tmux.conf
:
bind -T root C-M-j command-prompt -p 'dir:' "run-shell 'CD_TO_PANE=1 2>&1 _tmux-find-cwd \"%%\"'"
这样,当我按下Ctrl++时Alt,jtmux 会要求输入目录并为我运行脚本。非空CD_TO_PANE
变量使脚本cd
成为活动窗格的工作目录,因此相对路径可以方便地相对于我当前的窗格工作。
请注意,如果我输入typed string
,tmux 将使用以下命令字符串生成一个 POSIX shell:
CD_TO_PANE=1 2>&1 _tmux-find-cwd "typed string"
键入的字符串隐式地包含在双引号中,因此我不必担心等dir with spaces
。波浪号扩展不起作用,但来自生成的 shell 的环境的变量被扩展(例如$HOME
有效)。命令替换($(…)
)也有效。这不是注入代码的唯一方法。考虑这个键入的字符串:
/"; rm "foo
它将执行以下命令行:
CD_TO_PANE=1 2>&1 _tmux-find-cwd "/"; rm "foo"
所以请注意输入的内容。此漏洞是不可避免的,因为它run-shell
接受一个字符串,并且显然将其与 一起使用sh -c
。如果 tmux 可以首先创建一个适当的参数数组,那就更好了。在U&L SE 上的这个答案我们的代码%%
就像是{}
嵌入在 shell 代码中。我认为我们无能为力。单引号实际上帮不上什么忙,因为人们总是可以输入一个结束的引号,注入代码并重新打开引号。这可能是偶然的。例如,人们忘记了隐式引号,想要引用一个危险的字符串,使用额外的引号并有效地生成了被解析的未加引号的危险字符串。先见之明导致灾难。
也许最好选择这个变体:
bind -T root C-M-j command-prompt -p '$ _tmux-find-cwd' "run-shell 'CD_TO_PANE=1 2>&1 _tmux-find-cwd %%'"
这导致
CD_TO_PANE=1 2>&1 _tmux-find-cwd typed string
然后,您需要在需要时明确引用。波浪号扩展将起作用。代码注入就像输入一样简单;
。乍一看,这似乎更加危险,但我故意更改了提示符,使其看起来像是在交互式中输入命令sh
。如果您忘记是否应该引用,与 shell 的相似性应该是一个线索。
附加说明、怪癖和缺陷:
realpath
在这里非常有用,但是 POSIX 并不要求它。如果我的前提是错误的,而你真的想测试窗口的工作目录(不是所有窗格),那么你应该选择
tmux list-windows -F '#{window_id} #{pane_current_path}'
并相应调整其余代码。
我的代码一步即可检索
window_id
、pane_id
和pane_current_path
。通常,最好先获取pane_id
s 列表,然后对其进行迭代,然后为每个窗格分别检索其他信息(tmux display -p …
每个窗格可能具有多个信息)。理由:pane_current_path
可能包含换行符(换行符是文件名中的有效字符)。这会破坏我原来的代码。如果您一次检索一个路径,就可以解决这个问题。- 更复杂的逻辑可能依赖于您无法在一行中明确分隔(使用空格或其他方式)的格式。逐个检索它们可以解决问题。
- 命令替换
$(…)
会删除所有尾随换行符。我的代码使用它来解析路径。对于以换行符结尾的路径,这将失败。我想我可以修复代码,但会很麻烦。我不使用带换行符的路径,我想你也不用。 - 您可能想知道为什么我使用
realpath -e "$1//"
;为什么不?如果扩展到非目录的现有文件,realpath -e "$1"
后一个命令不会失败。结尾的斜杠告诉我期望一个目录,它可以节省我的时间。$1
realpath
[ -d … ]
- 为什么二斜线然后而不是一个?为了避免 bare
//
when$1
扩展到 sole/
(以防万一,请参阅这个答案)。