我有一个常见的用例,我想编写一个函数:我经常想要cd到相对于某个文件的某个目录。
$ gem which rspec/core | xargs echo -n | pbcopy
$ cd *paste and delete end until direcory looks right*
<子>
注意:gem which rspec/core
打印类似&#34; /Users/joshcheek/.rvm/gems/ruby-1.9.3-p125/gems/rspec-core-2.10.0/lib/rspec/core .RB&#34;
子>
$ gem which rspec/core | 2dir 3
这将把我带入&#34; /Users/joshcheek/.rvm/gems/ruby-1.9.3-p125/gems/rspec-core-2.10.0" (传递参数&#34; 3&#34;告诉它从最后删除&#34; lib / rspec / core.rb&#34;
2dir() {
read dir
for i in $(seq 1 $1)
do
dir="${dir%/*}"
done
cd "$dir"
}
但是cd改变了函数的目录,而不是我的。我尝试用别名交换它,但无法弄清楚如何制作匿名函数或传递论据。
答案 0 :(得分:9)
我会用:
2dir()
{
name=${2:?'Usage: 2dir count path'}
count=$1
while [[ $count -gt 0 ]]; do name=$(dirname "$name"); ((count--)); done
cd "$name"
}
并将其用作:
2dir 3 $(gem which rspec/core)
这适用于您的管道无法使用的地方。管道进程中的cd
会影响该(子)shell,但不会影响父进程的当前目录。可以使这个功能起作用。
如果您愿意,可以使用dir="${dir%/*}"
代替dirname
,除非您最终进入主目录而不是当前目录(或根目录,具体取决于是否如果在只有5个组件时指定10,则给出相对或绝对路径名称。
答案 1 :(得分:2)
这是@Jonathan Leffler关于简化使用的建议的一个变体 - 它使count参数可选,并且避免了命令周围$( )
的需要:
2dir() {
# If first arg is a number, use it as a trim count; otherwise assume 2
if [[ "$1" =~ ^[0-9]+$ ]]; then
count="$1"
shift
else
count=2
fi
if [[ $# -lt 1 ]]; then # Make sure a command was specified
echo "Usage: 2dir [count] command [commandargs ...]" >&2
return 1
fi
name="$("$@")" # Execute the remaining args as a command to get the target directory
while [[ $count -gt 0 ]]; do name=$(dirname "$name"); ((count--)); done
cd "$name"
}
示例用途:
2dir 3 gem which rspec/core
2dir gem which rspec/core
答案 2 :(得分:1)
命令
gem which rspec/core | 2dir 3
在shell的说法中被称为“管道”。管道中的每个命令都作为单独的进程执行。如果管道中的一个命令是shell函数,则它可以由当前(交互式)shell进程执行。但它不能保证,在你的情况下,这不会发生。
要解决您的问题,您只需确保在交互式shell中评估该功能。您只需要修复该功能,然后以不同方式使用它。这是更新的功能:
2dir() {
declare -ir snip="$1"
declare dir="$2"
for i in $(seq 1 "$snip"); do
dir="${dir%/*}"
done
cd "$dir"
}
你这样使用它:
$ 2dir 3 "$(gem which rspec/core)"
答案 3 :(得分:0)
shell脚本无法更改交互式shell的工作目录。只有一个别名可以做到这一点,因为它在你试图改变其目录的shell中运行。
换句话说:
有一个运行shell的Linux进程并接受来自您的命令。它有一个工作目录。当你告诉它执行一个shell脚本时,它会创建一个带有独立工作目录的全新流程,与第一个工作目录断开连接。
答案 4 :(得分:0)
根据Jonathan Leffler的回答,但没有循环:
2dir () {
local levels name=${2:?"Usage: $FUNCNAME count path"};
printf -v levels '%*s' "$1" '';
cd "/${name%${levels// //*}}"
}
一个令人烦恼的是,它使用perfectly valid生成leading double slashes目录(例如echo "$PWD"
输出&#34; // foo / bar / baz&#34;使用该函数后)。< / p>
另一个是它太聪明了一半。&#34;
修改强>
修正了双斜线问题:
2dir () {
local levels name=${2:?"Usage: $FUNCNAME count path"};
printf -v levels '%*s' $1 '';
name=/${name%${levels// //*}};
cd "${name/\/\///}"
}