Jak zdobyć pierwsze słowo ciągu?

43

Kiedy 'echo *' otrzymuję następujące dane wyjściowe:

file1 file2 file3 ...

Chcę wybrać pierwsze słowo. Jak mogę kontynuować?

Vdegenne
źródło
1
@mattdm Korzystanie lsnie działa, jeśli jeden z nazw plików zawiera spację.
helpermethod
2
Jak definiujesz słowo ? Jeśli pierwszy plik to Sunset on a beach.jpg, czy powinien to być Sunsetcały plik? Co Sea, sex and sun.ogg? Sea, Sea,Lub cała nazwa pliku?
Stéphane Chazelas
@mattdm ls | head -1daje mi losowe rzeczy, takie jak a.patch p.pyktóre nie jest pierwszym słowem, a nawet pliki w kolejności alfabetycznej.
phuclv

Odpowiedzi:

52

Możesz przerzucić go przez awk i sprawić, by powtórzył pierwsze słowo

echo * | head -n1 | awk '{print $1;}'

lub przeciąć ciąg i wybrać pierwsze słowo:

echo *  | head -n1 | cut -d " " -f1

lub potokujesz go przez sed i każesz usunąć wszystko oprócz pierwszego słowa

echo * | head -n1 | sed -e 's/\s.*$//'

Dodano, | head -n1aby zaspokoić nitpickers. W przypadku, gdy Twój ciąg zawiera nowe linie, | head -n1najpierw wybierze pierwszy wiersz, zanim ważne polecenia wybiorą pierwsze słowo z przekazanego mu ciągu.

Bananguin
źródło
1
Zwraca pierwsze słowo każdego wiersza, a nie pierwsze słowo.
Stéphane Chazelas
2
Zastanawiam się, ile linii echo *generuje
Bananguin
Zależy to od tego, ile plików ma w nazwie znaki nowego wiersza lub w zależności od środowiska, jak skompilowano bash, czy na liście pojawi się jakiś plik o nazwie -elub -ee..., ile czasu \npojawia się w nazwie pliku. Jeśli istnieje plik o nazwie -n, może nawet nie zwrócić żadnej linii ...
Stéphane Chazelas
Cóż, wciąż mówimy o bashu i 1. zwykle bash nie przejdzie ciągu z nowymi liniami jak jeden ciąg z nowymi liniami 2. bardzo trudno i nietypowo (niemożliwe?) Mieć nowy wiersz w nazwie pliku 3. a \ n w nazwa pliku pojawi się jako \ n 4. 3 wstrzymuje nazwy plików zaczynające się na - 5. nawet jeśli wywoływane przez -n lub -e echo otworzy standardowe wyjście i zamknie je, kiedy to zrobione, więc oczywiście zwróci linię i na przynajmniej jeden ciąg, jeśli chodzi o to 6. Zredagowałem moją radę, aby przynajmniej zająć się problemem multilinii
Bananguin
1
Wszystkie 5 punktów są fałszywe. Spróbuj w pustym katalogu: touch '$a\nb' 'a\nb'; env BASHOPTS=xpg_echo bash -c 'echo * | wc -l'( xpg_echojest włączony wszędzie tam, gdzie bashwymagana jest zgodność z Uniksem). A w innym pustym katalogu: touch ./-n; bash -c 'echo * | wc -l'. Linia to ciąg znaków zakończony znakiem nowej linii. Jeśli echonie wypisuje znaku nowej linii, nie wypisuje żadnego wiersza. Zachowanie narzędzi tekstowych podoba cut, awkczy sedjest nieokreślony, jeżeli wejście ma dodatkowych znaków po ostatni znak nowej linii i zachowanie różni się w poszczególnych wdrożeń.
Stéphane Chazelas,
18

Zakładając posixy shell ( /bin/shlub /bin/bashmożna to zrobić)

all=$(echo *)
first=${all%% *}

Konstrukt ${all%% *}jest przykładem usuwania podciągów . Te %%środki usuwać najdłuższy mecz *(spację cokolwiek) od końca prawej zmiennej all. Możesz przeczytać więcej o manipulowaniu łańcuchem tutaj .

To rozwiązanie zakłada, że ​​separator jest spacją. Jeśli robisz to z nazwami plików, każda ze spacjami to zepsuje.

rozgwiazdy
źródło
Niezłe. Ale podobała mi się prosta i bardziej nie zhakowana inna wersja z headicut
Anwar
4
IMO, head, cut & sed są mniej proste. Po co spawnować inne narzędzie, gdy wbudowane podstawienie parametrów wykonuje zadanie skutecznie. Ta odpowiedź jest najskuteczniejszym i najbardziej przenośnym sposobem na wybranie pierwszego słowa z listy słów rozdzielonych spacjami (o które poprosił OP).
Juan
7

Zakładając, że naprawdę potrzebujesz pierwszej nazwy pliku, a nie pierwszego słowa , oto sposób, który nie łamie się na białych znakach:

shopt -s nullglob
files=(*)
printf '%s\n' "${files[0]}"
Chris Down
źródło
1
Pierwsze słowo też byłoby łatwe:files=($(echo *))
Hauke ​​Laging
2
Uszkodziłoby to na „-n”, „-e”, „-ne”, „-Enenene” ... i zależnie od tego, jak bashzostało skompilowane lub środowisko, być może jednak na znakach odwrotnego ukośnika.
Stéphane Chazelas
2
@HaukeLaging, musisz wyłączyć globowanie. Na przykład: text=$(echo *); set -f; files=($text)w przeciwnym razie można by rozszerzyć więcej symboli wieloznacznych.
Stéphane Chazelas
3
ifiles=$(echo *); echo ${files%% *}
vdegenne
1
@memnoch_proxy Spowoduje to uszkodzenie nazw plików zawierających białe znaki, używaj go ostrożnie.
Chris Down
5

Możesz użyć parametrów pozycyjnych

set -- *
echo "$1"
Glenn Jackman
źródło
3
Pamiętaj, że spowoduje to zniszczenie wszelkich innych argumentów skryptu, chyba że zostanie uruchomiony w zakresie pomocniczym. Rozwinie się również, *jeśli w katalogu nie ma żadnych plików.
Chris Down,
shopt -s nullglobporadziłby sobie z tym
glenn jackman
3

Sprawdź jedną z następujących opcji:

$ FILE=($(echo *))
$ FILE=$(echo * | grep -o "^\S*")
$ FILE=$(echo * | grep -o "[^ ]*")
$ FILE=$(find . -type f -print -quit)

Następnie możesz go wydrukować za pomocą echo $FILE.

Zobacz także: grepjedyne pierwsze słowo z wyników?

kenorb
źródło
1

Uzyskiwanie całej pierwszej nazwy pliku:

shopt -s nullglob
printf '%s\000' * | grep -z -m 1 '^..*$'
printf '%s\000' * | ( IFS="" read -r -d "" var; printf '%s\n' "$var" )
markle
źródło