Come recuperare la prima parola dell'output di un comando in bash?


127

Ho un comando, per esempio: echo "word1 word2". Voglio mettere una pipe ( |) e ottenere word1 dal comando.

echo "word1 word2" | ....

Non so cosa mettere dopo la pipa.

Risposte:


201

Awk è una buona opzione se hai a che fare con gli spazi vuoti finali perché se ne occuperà per te:

echo "   word1  word2 " | awk '{print $1;}' # Prints "word1"

Cut non si prenderà cura di questo però:

echo "  word1  word2 " | cut -f 1 -d " " # Prints nothing/whitespace

'cut' qui non stampa nulla / spazi bianchi, perché la prima cosa prima di uno spazio era un altro spazio.


Il punto e virgola è necessario?
Alice Purcell

1
Dovrebbe essere uno spazio "iniziale" (all'inizio della stringa), non "finale".
user202729

@AlicePurcell l'ho provato senza; e ha funzionato per me (MBP 10.14.2)
Samy Bencherif

1
Questo non funziona se la stringa è ad esempio "firstWord, secondWord" come delimitatori del comando awk dallo spazio
Roger Oba,

@RogerOba Questa non era la domanda dell'OP, ma puoi usare -F","per sovrascrivere il separatore di campo predefinito (uno spazio) con una virgola.
pjd

70

non è necessario utilizzare comandi esterni. Bash stesso può fare il lavoro. Supponendo che "parola1 parola2" hai ricevuto da qualche parte e memorizzato in una variabile, ad es

$ string="word1 word2"
$ set -- $string
$ echo $1
word1
$ echo $2
word2

ora puoi assegnare $ 1 o $ 2 ecc. a un'altra variabile, se lo desideri.


11
+1 per utilizzare solo i built-in della shell e stdin. @ Matt M. --significa stdin, quindi $stringviene passato come stdin. stdinè separate da spazi in argomenti $1, $2, $3, ecc - proprio come quando un colpo valuta programma argomenti (ad esempio controllo $1, $2ecc), questo approccio sfrutta tendenza della shell di dividere la stdinin argomenti automaticamente, eliminando la necessità di awko cut.
Caleb Xu

3
@CalebXu Non stdin, setimposta gli argomenti della shell.
Guido

9
word1=$(IFS=" " ; set -- $string ; echo $1)Imposta IFS per riconoscere correttamente lo spazio tra le parole. Metti tra parentesi per evitare di rovinare il contenuto originale di $ 1.
Steve Pitchers

Questo è rotto poiché è soggetto all'espansione del nome del percorso. Provalo con string="*". Sorpresa.
gniourf_gniourf

32

Penso che un modo efficiente sia l'uso di array bash:

array=( $string ) # do not use quotes in order to allow word expansion
echo ${array[0]}  # You can retrieve any word. Index runs from 0 to length-1

Inoltre, puoi leggere direttamente gli array in una pipe-line:

echo "word1 word2" | while read -a array; do echo "${array[0]}" ; done

1
echo " word1 word2 " | { read -a array ; echo ${array[0]} ; }
Boontawee Home

Questo è rotto poiché è soggetto all'espansione del nome del percorso. Provalo con string="*". Sorpresa.
gniourf_gniourf

Usa la whilesintassi per recuperare ogni prima parola su ogni riga. Altrimenti, usa l'approccio Boontawee Home. Inoltre, tieni presente che echo "${array[0]}"è stato citato per prevenire l'espansione come notato da gniourf-gniourf.
Isaías

Se provi ad accedere a un indice di array che è maggiore del numero di parole, non otterrai un errore. Riceverai solo una riga vuota
Dhumil Agarwal

26
echo "word1 word2 word3" | { read first rest ; echo $first ; }

Ciò ha il vantaggio di non utilizzare comandi esterni e di lasciare intatte le variabili $ 1, $ 2, ecc.


Lasciare $1, $2, …intatte le variabili è una caratteristica estremamente utile per la scrittura di script!
Serge Stroobandt

15

Se sei sicuro che non ci siano spazi iniziali, puoi usare la sostituzione del parametro bash:

$ string="word1  word2"
$ echo ${string/%\ */}
word1

Attenzione per sfuggire al singolo spazio. Vedi qui per ulteriori esempi di modelli di sostituzione. Se hai bash> 3.0, puoi anche usare la corrispondenza delle espressioni regolari per far fronte agli spazi iniziali - vedi qui :

$ string="  word1   word2"
$ [[ ${string} =~ \ *([^\ ]*) ]]
$ echo ${BASH_REMATCH[1]}
word1

11

Potresti provare awk

echo "word1 word2" | awk '{ print $1 }'

Con awk è davvero facile scegliere qualsiasi parola ti piaccia ($ 1, $ 2, ...)


11

Utilizzo dell'espansione dei parametri della shell %% *

Ecco un'altra soluzione che utilizza l' espansione dei parametri della shell . Si occupa di più spazi dopo la prima parola. La gestione degli spazi davanti alla prima parola richiede un'espansione aggiuntiva.

string='word1    word2'
echo ${string%% *}
word1

string='word1    word2      '
echo ${string%% *}
word1

Spiegazione

Il %%significa l' eliminazione della corrispondenza più lunga possibile di  *(uno spazio seguito da qualsiasi numero di qualsiasi altro carattere) nella parte finale di string.


9

Mi chiedevo come molte delle risposte migliori fossero misurate in termini di velocità. Ho testato quanto segue:

1 @ mattbh's

echo "..." | awk '{print $1;}'

2 @ ghostdog74's

string="..."; set -- $string; echo $1

3 @ boontawee-home's

echo "..." | { read -a array ; echo ${array[0]} ; }

e 4 @ boontawee-home's

echo "..." | { read first _ ; echo $first ; }

Li ho misurati con il timeit di Python in uno script Bash in un terminale Zsh su macOS, utilizzando una stringa di prova con 215 parole di 5 lettere. Ogni misurazione è stata eseguita cinque volte (i risultati erano tutti per 100 loop, meglio di 3) e hanno calcolato la media dei risultati:

method       time
--------------------------------
1. awk       9.2ms
2. set       11.6ms (1.26 * "1")
3. read -a   11.7ms (1.27 * "1")
4. read      13.6ms (1.48 * "1")

Bel lavoro, elettori 👏 I voti (al momento della stesura di questo documento) corrispondono alla velocità delle soluzioni!


Strano che tu possa misurare 3 nel trattino, poiché il trattino non supporta gli array ( read -anon è valido nel trattino).
gniourf_gniourf

Sì, è strano. L'ho escluso, ho eseguito i test di velocità, poi ho pensato "perché l'ho lasciato fuori?" E l'ho aggiunto. Rimuovendolo ora, e potrei rieseguire le cose più tardi per assicurarmi di non aver commesso qualche errore
henry

6
echo "word1 word2" | cut -f 1 -d " "

cut taglia il 1 ° campo (-f 1) da un elenco di campi delimitati dalla stringa "" (-d "")


è un modo, ma la tua dichiarazione di taglio non distinguerà più spazi tra le parole se vuole ottenere word2 più tardi
ghostdog74

sì, la soluzione awk è la migliore.
lajuette

3

read È tuo amico:

  • Se la stringa è in una variabile:

    string="word1 word2"
    read -r first _ <<< "$string"
    printf '%s\n' "$first"
  • Se stai lavorando in una pipe: primo caso: vuoi solo la prima parola della prima riga:

    printf '%s\n' "word1 word2" "line2" | { read -r first _; printf '%s\n' "$first"; }

    secondo caso: vuoi la prima parola di ogni riga:

    printf '%s\n' "word1 word2" "worda wordb" | while read -r first _; do printf '%s\n' "$first"; done

Funzionano se ci sono spazi iniziali:

printf '%s\n' "   word1 word2" | { read -r first _; printf '%s\n' "$first"; }

0

Poiché perl incorpora le funzionalità di awk, questo può essere risolto anche con perl:

echo " word1 word2" | perl -lane 'print $F[0]'

0

Stavo lavorando con un dispositivo incorporato che non aveva né perl, awk o python e l'ho fatto con sed invece. Supporta più spazi prima della prima parola (che le soluzioni cute bashnon gestivano).

VARIABLE="  first_word_with_spaces_before_and_after  another_word  "
echo $VARIABLE | sed 's/ *\([^ ]*\).*/\1/'

Ciò è stato molto utile quando si cercano psID di processo poiché le altre soluzioni qui che utilizzano solo bash non sono state in grado di rimuovere i primi spazi che psutilizza per allineare.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.