How do I manipulate $PATH elements in shell scripts?

前端 未结 12 995
伪装坚强ぢ
伪装坚强ぢ 2020-11-28 04:03

Is there a idiomatic way of removing elements from PATH-like shell variables?

That is I want to take

PATH=/home/joe/bin:/usr/local/bin:/usr/bin:/bin:         


        
相关标签:
12条回答
  • 2020-11-28 04:36

    I prefer using ruby to the likes of awk/sed/foo these days, so here's my approach to deal with dupes,

    # add it to the path
    PATH=~/bin/:$PATH:~/bin
    export PATH=$(ruby -e 'puts ENV["PATH"].split(/:/).uniq.join(":")')
    

    create a function for reuse,

    mungepath() {
       export PATH=$(ruby -e 'puts ENV["PATH"].split(/:/).uniq.join(":")')
    }
    

    Hash, arrays and strings in a ruby one liner :)

    0 讨论(0)
  • 2020-11-28 04:41

    Just a note that bash itself can do search and replace. It can do all the normal "once or all", cases [in]sensitive options you would expect.

    From the man page:

    ${parameter/pattern/string}

    The pattern is expanded to produce a pattern just as in pathname expansion. Parameter is expanded and the longest match of pattern against its value is replaced with string. If Ipattern begins with /, all matches of pattern are replaced with string. Normally only the first match is replaced. If pattern begins with #, it must match at the beginning of the expanded value of parameter. If pattern begins with %, it must match at the end of the expanded value of parameter. If string is null, matches of pattern are deleted and the / following pattern may be omitted. If parameter is @ or *, the substitution operation is applied to each positional parameter in turn, and the expansion is the resultant list. If parameter is an array variable subscripted with @ or *, the substitution operation is applied to each member of the array in turn, and the expansion is the resultant list.

    You can also do field splitting by setting $IFS (input field separator) to the desired delimiter.

    0 讨论(0)
  • 2020-11-28 04:44

    This is easy using awk.

    Replace

    {
      for(i=1;i<=NF;i++) 
          if($i == REM) 
              if(REP)
                  print REP; 
              else
                  continue;
          else 
              print $i; 
    }
    

    Start it using

    function path_repl {
        echo $PATH | awk -F: -f rem.awk REM="$1" REP="$2" | paste -sd:
    }
    
    $ echo $PATH
    /bin:/usr/bin:/home/js/usr/bin
    $ path_repl /bin /baz
    /baz:/usr/bin:/home/js/usr/bin
    $ path_repl /bin
    /usr/bin:/home/js/usr/bin
    

    Append

    Inserts at the given position. By default, it appends at the end.

    { 
        if(IDX < 1) IDX = NF + IDX + 1
        for(i = 1; i <= NF; i++) {
            if(IDX == i) 
                print REP 
            print $i
        }
        if(IDX == NF + 1)
            print REP
    }
    

    Start it using

    function path_app {
        echo $PATH | awk -F: -f app.awk REP="$1" IDX="$2" | paste -sd:
    }
    
    $ echo $PATH
    /bin:/usr/bin:/home/js/usr/bin
    $ path_app /baz 0
    /bin:/usr/bin:/home/js/usr/bin:/baz
    $ path_app /baz -1
    /bin:/usr/bin:/baz:/home/js/usr/bin
    $ path_app /baz 1
    /baz:/bin:/usr/bin:/home/js/usr/bin
    

    Remove duplicates

    This one keeps the first occurences.

    { 
        for(i = 1; i <= NF; i++) {
            if(!used[$i]) {
                print $i
                used[$i] = 1
            }
        }
    }
    

    Start it like this:

    echo $PATH | awk -F: -f rem_dup.awk | paste -sd:
    

    Validate whether all elements exist

    The following will print an error message for all entries that are not existing in the filesystem, and return a nonzero value.

    echo -n $PATH | xargs -d: stat -c %n
    

    To simply check whether all elements are paths and get a return code, you can also use test:

    echo -n $PATH | xargs -d: -n1 test -d
    
    0 讨论(0)
  • 2020-11-28 04:47

    The first thing to pop into my head to change just part of a string is a sed substitution.

    example: if echo $PATH => "/usr/pkg/bin:/usr/bin:/bin:/usr/pkg/games:/usr/pkg/X11R6/bin" then to change "/usr/bin" to "/usr/local/bin" could be done like this:

    ## produces standard output file

    ## the "=" character is used instead of slash ("/") since that would be messy, # alternative quoting character should be unlikely in PATH

    ## the path separater character ":" is both removed and re-added here, # might want an extra colon after the last path

    echo $PATH | sed '=/usr/bin:=/usr/local/bin:='

    This solution replaces an entire path-element so might be redundant if new-element is similar.

    If the new PATH'-s aren't dynamic but always within some constant set you could save those in a variable and assign as needed:

    PATH=$TEMP_PATH_1; # commands ... ; \n PATH=$TEMP_PATH_2; # commands etc... ;

    Might not be what you were thinking. some of the relevant commands on bash/unix would be:

    pushd popd cd ls # maybe l -1A for single column; find grep which # could confirm that file is where you think it came from; env type

    ..and all that and more have some bearing on PATH or directories in general. The text altering part could be done any number of ways!

    Whatever solution chosen would have 4 parts:

    1) fetch the path as it is 2) decode the path to find the part needing changes 3) determing what changes are needed/integrating those changes 4) validation/final integration/setting the variable

    0 讨论(0)
  • 2020-11-28 04:50

    In line with dj_segfault's answer, I do this in scripts that append/prepend environment variables that might be executed multiple times:

    ld_library_path=${ORACLE_HOME}/lib
    LD_LIBRARY_PATH=${LD_LIBRARY_PATH//${ld_library_path}?(:)/}
    export LD_LIBRARY_PATH=${ld_library_path}${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}
    

    Using this same technique to remove, replace or manipulate entries in PATH is trivial given the filename-expansion-like pattern matching and pattern-list support of shell parameter expansion.

    0 讨论(0)
  • 2020-11-28 04:51

    suppose

    echo $PATH
    /usr/lib/jvm/java-1.6.0/bin:lib/jvm/java-1.6.0/bin/:/lib/jvm/java-1.6.0/bin/:/usr/lib/qt-3.3/bin:/usr/lib/ccache:/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin:/home/tvnadeesh/bin
    

    If you want to remove /lib/jvm/java-1.6.0/bin/ do like as below

    export PATH=$(echo $PATH | sed  's/\/lib\/jvm\/java-1.6.0\/bin\/://g')
    

    sed will take input from echo $PATH and replace /lib/jvm/java-1.6.0/bin/: with empty

    in this way you can remove

    0 讨论(0)
提交回复
热议问题