【问题标题】:Use path of source in a scala script file在 Scala 脚本文件中使用源路径
【发布时间】:2012-04-04 20:34:23
【问题描述】:

我正在寻找一种方法来使用由执行的 *.scala 文件的完整路径

scala /path/to/file/file.scala 

原因是在我的脚本中我想使用相对于 file.scala 保存位置的路径。所以,假设我想在调用 file.scala 时从 file.scala 内部调用 /path/to/file/file_second.scala

scala ./to./file/file.scala 

因为我从中调用 scala 的目录是 /path (即 System.getProperty("user.dir") 将返回的内容)。我所知道的先验是 file_second.scala 与 file.scala 位于同一目录中,但实际上并不知道完整路径。

我试过了。其中包括 getClass.getResource("").split(":")(1),但这将 返回 /path/./ 或 /tmp/scala.tmp/

我想必须有一个干净的解决方案,因为 scala -savecompiled 会在我想要处理的那个目录中创建一个 *.jar,但我就是不知道如何......:/

非常感谢您的帮助。

【问题讨论】:

  • 我想添加一个我从第二个答案开发的解决方案(当我几周前阅读它时,我还没有阅读答案 Nr.1),用于在 linux 系统上调用的 scala 脚本。这是我现在使用的方式。谢谢大家的回答,我从中学到了很多!我只是不知道将哪个答案标记为“已接受”。解决办法:
  • #! /bin/bash INSTALL_DIR="$( cd "$( dirname "BASH_SOURCE[0]" )" && pwd )" exec scala -savecompiled -DPARAM_INSTALL_DIR=$INSTALL_DIR "$0" "$@" !# val install_dir = System.getProperty ("PARAM_INSTALL_DIR") + java.io.File.separator

标签: scala file path


【解决方案1】:

脚本序言:

#!/bin/sh
export SCRIPT_PATH=$(readlink -f "$0") && exec scala "$0" "$@"
!#

读取值:

val scriptPath = System.getenv("SCRIPT_PATH")

【讨论】:

  • 这是最好的答案(和往常一样,它是最后一个)。
  • export SCRIPT_DIR="$(dirname "$(readlink -f "$0")")" && exec scala "$0" "$@"
【解决方案2】:

我过去在 Java 中做过这个。它并不漂亮,而且可能不是 100% 可靠,具体取决于您的类加载器情况的详细信息。

这是一些打印出自己的类文件位置的 Scala 代码。

import java.net.URL

object LocationTest extends App {
  val classDirURL = LocationTest.getClass.getResource("LocationTest.class")
  val classDirPath = classDirURL.getPath.replaceAll("%20", " ")
  println(classDirPath)
}

打印

/Users/connor/desktop/LocationTest.class

【讨论】:

    【解决方案3】:

    以下脚本将打印它的文件系统路径。连续尝试三种不同的方法,直到其中一种成功。

    import java.io.File
    
    printf("[%s]\n",new File(getScriptName).getCanonicalPath)
    System.exit(0)
    
    def getScriptName:String = {
      // this approach works on the sun jvm:
      val jcmd = System.getProperty("sun.java.command","")
      jcmd.split("""\s+""").toList.reverse.head match {
      case name if new File(name).exists => name
      case _ =>
        // for this to work, you need to set -Dscala.script.name at script launch
        System.getProperty("scala.script.name","") match {
        case name if new File(name).exists => name
        case _ =>
          // last resort: derive script basename from stackdump
          val basename = {
            val filenames = new RuntimeException("").getStackTrace.map { it
              => it.getFileName
            }
            filenames.indexOf("NativeMethodAccessorImpl.java") match {
              case -1 =>  filenames.reverse.head
              case num => filenames(num - 1)
            }
          }
          // then search the system PATH for the script file
          import scala.collection.JavaConversions._
          val sep = System.getProperty("path.separator")
          val path = System.getenv("PATH").split(sep)
          path.map(new File(_,basename)).find( _.exists ) match {
            case Some(scriptfile) => scriptfile.getCanonicalPath
            case _ => basename // better than nothing
          }
        }
      }
    }
    

    最简单和最可移植的是第二种方法,它依赖于使用包装脚本,如下例所示,用于在调用 $SCALA_HOME/bin/scala 之前定义属性“scala.script.name”。当然,包装脚本需要位于 $SCALA_HOME/bin 之前的 PATH 中。结果更加防弹,但仅适用于脚本。

    #!/usr/bin/env sh
    for SCRIPT_NAME; do true ; done # set SCRIPT_NAME to the last argument
    JAVA_OPTS="$JAVA_OPTS -Dscala.script.name=${SCRIPT_NAME}"
    $SCALA_HOME/bin/scala "$@"
    

    在 scala 启动器周围使用此包装器可将使用简化为以下内容:

    #!/usr/bin/env scala
    !#
    printf("%s\n",System.getProperty("scala.script.name"))
    

    【讨论】:

      【解决方案4】:

      您可以使用参数调用您的程序:

      scala -DPARAM_DIR=tmp Foo
      

      并检查程序内部的参数:

      object Foo extends App {
        val dir = System.getProperty ("PARAM_DIR")
        println ("Dir: " + dir) 
      }
      

      所以这不会(必然)使用 Foo.scala 所在的同一个目录,但它会很灵活,并且可以在运行时被告知在哪里寻找一个类。

      在正常情况下,您可以将类捆绑在一个 Jar 中,或者设置一个公共类路径,然后您可能会拥有一个相对于类路径解析的包:

      对于一个类到.file.File中

       /path/to/file/file.scala 
      

      它将是类路径/path,对于包file 中的类文件,它将是/path/to/。

      如果您的类路径是 /path/to/file,则第二个类应该可以通过名称访问。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-07-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多