【问题标题】:How to concatenate two strings to build a complete path如何连接两个字符串以构建完整路径
【发布时间】:2012-06-27 12:34:16
【问题描述】:

我正在尝试编写一个 bash 脚本。在此脚本中,我希望用户输入目录的路径。然后我想在这个字符串的末尾附加一些字符串并建立一个到一些子目录的路径。 例如假设用户输入这样的字符串:

/home/user1/MyFolder

现在我想在这个目录下创建2个子目录,然后复制一些文件到那里。

/home/user1/MyFolder/subFold1
/home/user1/MyFolder/subFold2

我该怎么做?

【问题讨论】:

  • 到目前为止您尝试过什么?另外,您的问题的一部分是关于从用户那里获得输入,而另一部分是关于构建路径?还是只是路径?

标签: linux bash


【解决方案1】:

POSIX 标准要求将多个 / 视为文件名中的单个 /。因此 //dir///subdir////file/dir/subdir/file 相同。

因此,连接两个字符串以构建完整路径很简单:

full_path="$part1/$part2"

【讨论】:

  • 除非 $part1 可以是空字符串。
  • @TuureLaurinolli 我不明白你来自哪里。上述串联仍会产生有效路径。该路径可能不存在,但仍然有效。例如。 "" + "/" + "Documents""/Documents"
  • 如果part本身是相对路径,part1可能为空,那么结果可能会从相对路径转为绝对路径。
  • @TuureLaurinolli 然后你可以简单地在前面添加./。但也许用户想要连接绝对路径。否则,他们可以简单地将./ 添加到前面以强制路径是相对的。另请注意,"$path1/./$path2""$path1/$path2" 相同。
【解决方案2】:
#!/bin/bash

read -p "Enter a directory: " BASEPATH

SUBFOLD1=${BASEPATH%%/}/subFold1
SUBFOLD2=${BASEPATH%%/}/subFold2

echo "I will create $SUBFOLD1 and $SUBFOLD2"

# mkdir -p $SUBFOLD1
# mkdir -p $SUBFOLD2

如果您想使用 readline 来完成所有操作,请在对 read 的调用中添加 -e

read -e -p "Enter a directory: " BASEPATH

【讨论】:

  • 不幸的是,当 BASEPATH 为空时,这不起作用。我需要的是这样的东西,它只在它还没有以斜杠结尾并且不为空时添加一个 / 。因此,当它以合​​法的文件名字符结尾时。
  • BASEPATH 为空是一种特殊情况,因此不要指望单行。但是,这应该适用于您的情况: [ -z $BASEPATH ] && BASEPATH='.';全路径=${BASEPATH%%/}/subfolder1;回声 $fullpath;结果:./subfolder1
【解决方案3】:

简单地连接你的路径部分不会完成你想要的吗?

$ base="/home/user1/MyFolder/"
$ subdir="subFold1"
$ new_path=$base$subdir
$ echo $new_path
/home/user1/MyFolder/subFold1

然后您可以根据需要创建文件夹/目录。

一种约定是以/(例如/home/)结束目录路径,因为以/开头的路径可能与根目录混淆。如果在路径中使用双斜杠 (//),它仍然是正确的。但是,如果两个变量都没有使用斜线,那就是不正确的(例如/home/user1/MyFoldersubFold1)。

【讨论】:

  • 为什么我会收到这条消息:Myscript.sh: line 4: /home/user1/MyFolder/subFold1: Is a directory
  • 路径中缺少 /。目标是内联/home/user1/MyFolder/subFold1,因此您需要内联new_path=$base/$subdir。但是,如果给定的路径包含尾随的“/”,你会怎么做?
  • @Thrasi 只需将尾随 '/' 添加到 subdir 变量或 newpath=$base/$subdir/ 你可以直接在命令行上玩这个
  • @user12345,是的......仍然使上述解决方案不正确。
【解决方案4】:

以下脚本将多个(相对/绝对)路径 (BASEPATH) 与相对路径 (SUBDIR) 连接起来:

shopt -s extglob
SUBDIR="subdir"
for BASEPATH in '' / base base/ base// /base /base/ /base//; do
  echo "BASEPATH = \"$BASEPATH\" --> ${BASEPATH%%+(/)}${BASEPATH:+/}$SUBDIR"
done

其输出为:

BASEPATH = "" --> subdir
BASEPATH = "/" --> /subdir
BASEPATH = "base" --> base/subdir
BASEPATH = "base/" --> base/subdir
BASEPATH = "base//" --> base/subdir
BASEPATH = "/base" --> /base/subdir
BASEPATH = "/base/" --> /base/subdir
BASEPATH = "/base//" --> /base/subdir

shopt -s extglob 只需要允许 BASEPATH 以多个斜杠结尾(这可能是无稽之谈)。没有扩展的全局,你可以使用:

echo ${BASEPATH%%/}${BASEPATH:+/}$SUBDIR

这会导致不那么整洁但仍然有效:

BASEPATH = "" --> subdir
BASEPATH = "/" --> /subdir
BASEPATH = "base" --> base/subdir
BASEPATH = "base/" --> base/subdir
BASEPATH = "base//" --> base//subdir
BASEPATH = "/base" --> /base/subdir
BASEPATH = "/base/" --> /base/subdir
BASEPATH = "/base//" --> /base//subdir

【讨论】:

    【解决方案5】:

    我正在使用我的 shell 脚本,它需要像你一样做一些路径连接的东西。

    问题是,两条路径都像

    /data/foo/bar
    
    /data/foo/bar/ 
    

    有效。

    如果我想将文件附加到此路径,例如

    /data/foo/bar/myfile
    

    shell 中没有本地方法(如 python 中的 os.path.join())来处理这种情况。

    但我确实发现了一个窍门

    例如,基本路径存储在 shell 变量中

    BASE=~/mydir
    

    你想加入的最后一个文件名是

    FILE=myfile
    

    然后你可以像这样分配你的新路径

    NEW_PATH=$(realpath ${BASE})/FILE
    

    然后你会得到

    $ echo $NEW_PATH
    
    /path/to/your/home/mydir/myfile
    

    原因很简单,如果需要,“realpath”命令总是会为你修剪终止斜线

    【讨论】:

      【解决方案6】:

      这应该适用于空目录(您可能需要检查第二个字符串是否以/ 开头,这应该被视为绝对路径?):

      #!/bin/bash
      
      join_path() {
          echo "${1:+$1/}$2" | sed 's#//#/#g'
      }
      
      join_path "" a.bin
      join_path "/data" a.bin
      join_path "/data/" a.bin
      

      输出:

      a.bin
      /data/a.bin
      /data/a.bin
      

      参考:Shell Parameter Expansion

      【讨论】:

      • 如果有三个或更多的斜线怎么办?您可以使用递归的sed 调用,也就是sed -e ':loop' -e 's#//#/#' -e 't loop'。 (表单与非 POSIX 实现兼容。)
      【解决方案7】:
      #!/usr/bin/env bash
      
      mvFiles() {
          local -a files=( file1 file2 ... ) \
                   subDirs=( subDir1 subDir2 ) \
                   subDirs=( "${subDirs[@]/#/$baseDir/}" )
      
          mkdir -p "${subDirs[@]}" || return 1
      
          local x
          for x in "${subDirs[@]}"; do
              cp "${files[@]}" "$x"
          done
      }
      
      
      
      main() {
          local baseDir
          [[ -t 1 ]] && echo 'Enter a path:'
          read -re baseDir
          mvFiles "$baseDir"
      }
      
      main "$@"
      

      【讨论】:

        【解决方案8】:

        我最终将所有参数 ($*) 与 '/' (IFS=/ - Internal F使用 Separator) 作为分隔符,然后删除所有重复的 '/' (tr -s /)。

        我的函数如下所示:

        join_paths() {
            (IFS=/; echo "'$*'" | tr -s /)
        }
        

        【讨论】:

          猜你喜欢
          • 2020-08-27
          • 2015-05-13
          • 2011-09-11
          • 2022-08-18
          • 1970-01-01
          • 2023-03-07
          • 1970-01-01
          • 2011-11-04
          相关资源
          最近更新 更多