ubuntuusers.de

Bash: $@ auseinandernehmen

Status: Gelöst | Ubuntu-Version: Nicht spezifiziert
Antworten |

schlonz

Avatar von schlonz

Anmeldungsdatum:
30. November 2005

Beiträge: 294

Wohnort: berlin

Mein Skript soll eine Reihe von Argumenten übernehmen können, wobei erstes bis vorletztes Argument Quelldateien sein sollen, das letzte Argument dann ist die Zieldatei.

Ich suche also nach einem eleganten weg um $@ in zwei Variablen aufzuspalten:
$quellen enthält den Substring einschliesslich bis zum vorletzten Token
$ziel enthält nur das letzte Token

Ich könnte in einer Schleife alles mit shift auseinandernehmen und wieder zusammensetzen, aber es gibt bestimmt einen schöneren Weg dafür?
Die Bash hat ja einiges an Stringmanipulationsmöglichkeiten an Bord..

MrKanister

Anmeldungsdatum:
13. Oktober 2007

Beiträge: 2105

Schlagt mich von mir aus für die Komplexität...aber ich mag's 😀 :

#!/bin/bash

argumente_bis_zum_vorletzten=$(eval eval echo \\\${1..$(($# - 1))})
letztes_argument=${!#}

echo $argumente_bis_zum_vorletzten
echo $letztes_argument

Es gibt bestimmt noch einen schöneren Weg, aber einen schnelleren bestimmt nicht;)

martin@martin-desktop:~$ example2 1 2 3 4 5
1 2 3 4
5

Gruß Martin

audax

Avatar von audax

Anmeldungsdatum:
15. September 2006

Beiträge: 1253

Öhm...in der Bash bekomme ich es auch grad nicht hin...

So jedenfalls in der Zsh:

#!/bin/zsh
echo ${@[-1]} # letztes Argument
echo ${@[0,-2]} # alle bis auf das Letzte

MrKanister

Anmeldungsdatum:
13. Oktober 2007

Beiträge: 2105

Darf ich bei dieser Gelegenheit erwähnen, dass ich langsam anfange die Zsh exorbitant geil zu finden 😲

MrKanister

Anmeldungsdatum:
13. Oktober 2007

Beiträge: 2105

Hier vielleicht noch eine Variante für Normalsterbliche, die zu faul sind, sich die Zsh zu installieren 😀

argumente_bis_zum_vorletzten=""
for i in $(seq $(($# - 1)))
do
    argumente_bis_zum_vorletzten=$(echo $argumente_bis_zum_vorletzten ${!i})
done
    
letztes_argument=${!#}

echo $argumente_bis_zum_vorletzten
echo $letztes_argument


Die Zeile

argumente_bis_zum_vorletzten=""


kann man auch weglassen, wenn man auf "unbound variable" steht 😉

audax

Avatar von audax

Anmeldungsdatum:
15. September 2006

Beiträge: 1253

Und so ginge es ordentlich 😉

#!/bin/bash
declare -a sources
i=0
until [[ -z $2 ]]
do
   sources[i]=$1
   shift
   i=$((i+1))
done
echo $@ # letztes argument
echo ${sources[*]} # rest

Bäh, Bash stinkt 😉

MrKanister

Anmeldungsdatum:
13. Oktober 2007

Beiträge: 2105

audax hat geschrieben:

Bäh, Bash stinkt 😉

Wie wäre es zur Abwechselung mal mit einem Bash-Bashing ?

audax

Avatar von audax

Anmeldungsdatum:
15. September 2006

Beiträge: 1253

Abwechslung? Eigentlich ist das bei mir die Regel 😉

Btw, ich hatte eine Unschönheit:

#!/bin/bash
declare -a sources
i=0
until [[ -z $2 ]]
do
   sources[i]=$1
   shift
   let "i++"
done
echo $@
echo ${sources[*]}


Trotzdem bäh.

schlonz

(Themenstarter)
Avatar von schlonz

Anmeldungsdatum:
30. November 2005

Beiträge: 294

Wohnort: berlin

Schönen Dank für die Hilfe. Ich hab ein paar Minuten vor der ersten Antwort selber auch eine Lösung via Array gefunden, ist aber mit vier Zeilen inakzeptabel aufwendig und kömmt nicht an Eure Zweizeiler ran ☺
Wobei ich gestehen muß, daß ich die Zeile mit dem eval eval nicht so ganz verstehe.

Um mich mal der Code-Parade anzuschließen: Via Array:

#!/bin/bash

args=($@)
let lastIndex=${#args[*]}-1
targetFile=${args[lastIndex]}
args[lastIndex]=""

echo $targetFile
echo ${args[*]}

P.S.: Ich hab mich ja bisher gesträubt, aber vielleicht muß ich mir doch mal die Zsh näher anschauen ♥

audax

Avatar von audax

Anmeldungsdatum:
15. September 2006

Beiträge: 1253

Ah...$@ ist in der Bash also kein echtes Array!

Diese Shell ist dermaßen inkonsistent.. /o

MrKanister

Anmeldungsdatum:
13. Oktober 2007

Beiträge: 2105

schlonz hat geschrieben:

Wobei ich gestehen muß, daß ich die Zeile mit dem eval eval nicht so ganz verstehe.

Mit einem eval wird der Code 2x ausgeführt. Mit 2 eval's wird der Code 3x ausgeführt...

Bei einem Beispiel von 5 Argumenten:

Aus

\\\${1..$(($# - 1))} 


wird

\${1..4} 


wird

$1 $2 $3 $4

.

Das ist alles 😉

audax

Avatar von audax

Anmeldungsdatum:
15. September 2006

Beiträge: 1253

Klappt aber leider nicht mit 10 oder mehr Argumenten 😉

MrKanister

Anmeldungsdatum:
13. Oktober 2007

Beiträge: 2105

Komischerweise tut es das doch...wobei ich mich im Moment Frage warum 😲

#!/bin/bash

argumente_bis_zum_vorletzten=$(eval eval echo \\\${1..$(($# - 1))})
letztes_argument=${!#}

echo $argumente_bis_zum_vorletzten
echo $letztes_argument
martin@martin-desktop:~$ example2 1 2 3 4 5 6 7 8 9 10 11 12 13 14
1 2 3 4 5 6 7 8 9 10 11 12 13
14


EDIT: Oh...

martin@martin-desktop:~$ example2 1 2 3 4 5 6 7 8 9 foo bar
1 2 3 4 5 6 7 8 9 10
bar

MrKanister

Anmeldungsdatum:
13. Oktober 2007

Beiträge: 2105

Ok...dann ergänzen wir die ohne hin schon verstümmelte Zeile eben ein wenig 😉

#!/bin/bash

argumente_bis_zum_vorletzten=$(eval eval echo \\\$\{{1..$(($# - 1))}\})
letztes_argument=${!#}

echo $argumente_bis_zum_vorletzten
echo $letztes_argument
martin@martin-desktop:~$ example2 1 2 3 4 5 6 7 8 9 foo bar
1 2 3 4 5 6 7 8 9 foo
bar

schlonz

(Themenstarter)
Avatar von schlonz

Anmeldungsdatum:
30. November 2005

Beiträge: 294

Wohnort: berlin

Mr. Kanister hat geschrieben:

Das ist alles 😉

Ok.. so langsam versteh ich's ☺
Trickreich!

audax hat geschrieben:

Ah...$@ ist in der Bash also kein echtes Array!

Diese Shell ist dermaßen inkonsistent.. /o\\

Yo.. wenn ich's richtig verstanden hab, dann ist $@ ein String. Ist aber im nu in ein Array umgewandelt ☺
Inkosistent hin oder her, was mich an Bash am meisten stört, ist das es außer dem Quellcode nirgends ein Dokument zu geben scheint, das einfach mal alle Features zum Nachschlagen auflistet. Alles muß man sich aus Tutorials zusammenklauben.

Antworten |