bash:将字符串变量解释为文件名/路径

问题描述 投票:0回答:4

我的 bash 脚本接收字符串形式的文件名(或相对路径),但必须从该文件中读取。如果我直接在脚本中将其声明为文字(不带引号),我只能从文件名中读取...这对于参数来说是不可能的,因为它们一开始就是隐式字符串。观察:

a="~/test.txt"
#Look for it
if [[ -a $a ]] ; then
    echo "A Found it"
else
    echo "A Error"
fi
#Try to use it
while read line; do
    echo $line
done < $a

b='~/test.txt'
#Look for it
if [[ -a $b ]] ; then
    echo "B Found it"
else
    echo "B Error"
fi
#Try to use it
while read line; do
    echo $line
done < $b

c=~/test.txt
#Look for it
if [[ -a $c ]] ; then
    echo "C Found it"
else
    echo "C Error"
fi
#Try to use it
while read line; do
    echo $line
done < $c

产量:

A Error
./test.sh: line 10: ~/test.txt: No such file or directory
B Error
./test: line 12: ~/test.txt: No such file or directory
C Found it
Hello

如上所述,我无法将命令行参数传递给上面的例程,因为我得到的行为与在带引号的字符串上得到的行为相同。

string bash filenames
4个回答
58
投票

这是

~
扩展规则的一部分。 Bash 手册中明确指出,当引用
~
时,不会执行此扩展。

解决方法1

请勿引用

~

file=~/path/to/file

如果您需要引用文件名的其余部分:

file=~/"path with spaces/to/file"

(这在普通 shell 中是完全合法的。)

解决方法2

使用

$HOME
代替
~

file="$HOME/path/to/file"

顺便说一句:Shell 变量类型

您似乎对 shell 变量的类型有点困惑。

一切都是字符串。

重复直到理解:一切都是字符串。(除了整数,但它们大多是字符串之上的黑客据我所知。还有数组,但它们是字符串的数组。)

这是一个 shell 字符串:

"foo"
"42"
也是如此。
42
也是如此。
foo
也是如此。如果你不需要引用某些东西,那么不引用也是合理的;谁想输入
"ls" "-la" "some/dir"


0
投票

仍然不那么迷人,但对我有用:

home_folder="/home/$(logname)"

可以从那里工作...


0
投票

最终解决方法

为了补充michaelb958的正确答案,我建议使用模式替换,来自bash的参数扩展(参见

man -P'less +/pattern\ substitution' bash
):

file='~/test.txt'
ls "${file/#~\//$HOME\/}"   # This could be double-quoted
/home/user/test.txt

当然这可以用于两种方式:

file="$HOME/test.txt"
echo "${file/#$HOME\//\~\/}"
~/test.txt

使用
sed
过滤输出:

为了避免与任何类型的

$HOME
路径发生冲突,我将使用
;
作为
sed
s
命令:

ls -ld ~/* | sed "s;$HOME;~;"
drwxr-xr-x   5 user user   4096 12 jui 16:36 ~/Documents
drwxr-xr-x   5 user user   4096 12 jui 16:36 ~/Desktop
-rw-r--r--   1 user user      0 10 sep 12:34 ~/test.txt
...

0
投票

支持“F. Hauri - 放弃 GitHub”, 当自动使用路径作为包含环境变量的字符串时,使用模式替换非常有用,例如。 $HOME。例如,将 KDE dolphin 中的链接转换为包含 URL 的文件,该文件包含指向包含 $HOME 的文本字符串目标。从包含 $HOME 的 dolphin 链接 URL 创建符号链接的脚本失败。我的解决方法是使用模式替换来替换 /home/$USER 环境变量 $HOME。 作为示例,下面的脚本用于创建自定义操作,以将 xfce4 Thunar 中选择的 KDE dolphin 链接更改为符号链接。链接名称只是一个以逗号分隔的目标路径反向列表。 该脚本无法识别 $HOME,因此使用路径替换将其更改为 /home/$USER。

#!/bin/bash
# file: cnv_kde-to-symb_link.sh
# date: 20240404
# desc: Convert a link created in KDE dolphin to a symbolic link
# usge: cnv_kde-to-symb_link.sh %ln
# usge: %ln is the KDE dolphin link

string=`grep URL $1 | sed 's/^.*binder\/\(.*\)$/\1/'`
fstring=`grep URL $1 | sed 's/^.*file:\(.*\)$/\1/'`
fstring="${fstring/#\$HOME\//\/home\/$USER\/}"

#Split the path using "/" into an array of directory names
readarray -d "/" -t array <<< "$string"

# Build the link name by reversing the directory names in the path
lnk="_"
sep=""
element=""
# To evaluate an integer expression use $(($var-int))
cnt=$((${#array[@]}-1))
# for ((i=${#array[@]}-1; i>=0; i--)); do
for ((i=$cnt; i>=0; i--)); do
    if [ $i -lt $cnt ]; then sep=","; fi
        # Strip leading or trailing spaces, condense multi-space to single space
        element=`echo ${array[$i]} | xargs`
        lnk=$lnk$sep$element
done

# Create the symbolic link
lstring=$lnk"_ln"
ln -s $fstring ./$lstring
© www.soinside.com 2019 - 2024. All rights reserved.