使用“ls”仅显示源文件和目标链接文件

使用“ls”仅显示源文件和目标链接文件

我可以使用以下命令显示链接指向的目标文件ls -l

snowch$ ls -l /usr/local/bin/mvn
lrwxr-xr-x  1 snowch  admin  29 12 Dec 08:58 /usr/local/bin/mvn -> ../Cellar/maven/3.2.3/bin/mvn

有没有一种方法可以显示更少的输出,而无需通过其他命令(例如 awk)进行管道传输?例如:

snowch$ ls ?? /usr/local/bin/mvn
/usr/local/bin/mvn -> ../Cellar/maven/3.2.3/bin/mvn

我在 OS X 10.9.5 上运行 3.2.53。几个命令的输出如下所示:

snowch$ ls -H /usr/local/bin/mvn
/usr/local/bin/mvn

snowch$ ls -L /usr/local/bin/mvn
/usr/local/bin/mvn

snowch$ file /usr/local/bin/mvn
/usr/local/bin/mvn: POSIX shell script text executable

snowch$ file -b /usr/local/bin/mvn
POSIX shell script text executable

答案1

ls不幸的是,没有检索文件属性并以任意方式显示它们的选项。有些系统为此有单独的命令(例如 GNU 有一个stat命令或 GNU 中的功能find)。

在大多数现代系统上,对于大多数文件,这应该可以工作:

$ ln -s '/foo/bar -> baz' the-file
$ LC_ALL=C ls -ldn the-file | sed '
   1s/^\([^[:blank:]]\{1,\}[[:blank:]]\{1,\}\)\{8\}//'
the-file -> /foo/bar -> baz

其工作原理是删除 输出第一行的前 8 个空白分隔字段ls -l。这应该可以工作,除非系统上不显示 gid,或者当存在大量链接时前两个字段连接在一起。

使用 GNU stat

$ LC_ALL=C stat -c '%N' the-file
'the-file' -> '/foo/bar -> baz'

使用 GNU find

$ find the-file -prune \( -type l -printf '%p -> %l\n' -o -printf '%p\n' \)
the-file -> /foo/bar -> baz

对于 FreeBSD/OS/X 统计:

f=the-file
if [ -L "$f" ]; then
  stat -f "%N -> %Y" -- "$f"
else
  printf '%s\n' "$f"
fi

zsh统计:

zmodload zsh/stat
f=the-file
zstat -LH s -- "$f"
printf '%s\n' ${s[link]:-$f}

许多系统还有readlink专门获取链接目标的命令:

f=the-file
if [ -L "$f" ]; then
  printf '%s -> ' "$f"
  readlink -- "$f"
else
  printf '%s\n' "$f"
fi

答案2

使用file命令。

[sreeraj@server ~]$ ls -l mytest
lrwxrwxrwx 1 sreeraj sreeraj 15 Dec 12 09:31 mytest -> /usr/sbin/httpd

[sreeraj@server ~]$ file mytest
mytest: symbolic link to `/usr/sbin/httpd'

或者

[sreeraj@server ~]$ file -b mytest
symbolic link to `/usr/sbin/httpd'
[sreeraj@server ~]$

另外,请阅读 的手册页ls并检查选项-L-H看看是否能满足您的要求。

答案3

ls至少有 GNU(显然,tcsh还有 的实现)您可以修改$LS_COLORS环境变量以在您喜欢的位置插入分隔符(但是tcsh的内置函数ls-F不执行链接目标 - 仅链接标志通常ls根据该环境变量中存储的值插入任意不可打印的终端转义符,但是没有什么可以阻止我们插入任意其他内容。更多关于此这里

例如:

LS_COLORS='ln=///\n:lc=:no=//:rc=:rs=:' \
\ls ~ -l --color=always | 
sed '\|///|,\|//|!d;//d'

//这会在每个列表的开头放置一个字符串(所以就在之前lrwcrwx以及///\n任何链接的文件名之前的 。sed然后过滤行范围 - 它将d删除每个输入行,直到遇到它///,然后从那里到下一个匹配的行将//删除匹配的行//。因此它只获取链接名称和链接目标 - 无论中间的字符如何。这是因为/不能出现在文件名中 - 并且任何路径中的那些ls可能打印只会单独出现。

看?

mkdir test; cd test
touch 'long


name' shortname
ln -s l* "$(printf %s.ln l*)"; ln -s s* shortname.ln

LS_COLORS='ln=///\n:lc=:no=//:rc=:rs=:' \
\ls  -l --color=always | sed '\|///|,\|//|!d;//d'

...打印:

long


name.ln -> long


name
shortname.ln -> shortname

自己尝试一下。

答案4

[在 Linux/Bash 上]

我会这样做:

ls -l | sed -e"s/ \+/ /g" | cut -d' ' -f 9-

sed命令将多个空格折叠为单个空格;提取cut第 9 个字段,其中字段分隔符是空格。

典型输出:

libboost_atomic.a
libboost_atomic.so -> libboost_atomic.so.1.57.0
libboost_atomic.so.1.57.0
...
libboost_wserialization.a
libboost_wserialization.so -> libboost_wserialization.so.1.57.0
libboost_wserialization.so.1.57.0

替代方案是:

ls -l | awk '{ print $9, $10, $11 }'
ls -l | awk '{ $1 = $2 = $3 = $4 = $5 = $6 = $7 = $8 = "" ; print }'

但这些都是不完美的:第一个可以输出尾随空格;第二个,前导空格。

相关内容