Dlaczego to polecenie xargs nie działa?

14

Chciałem usunąć wszystkie rozszerzenia .sh, więc zrobiłem to:

ls *.sh | xargs -I {} mv {} `basename {} .sh`

Jednak to nie działa, zachowuje się jak basenamezwraca niezmienioną nazwę pliku.

Dlaczego tak się zachowuje?

Na przykład działa to:

ls *.sh | xargs -I {} echo `basename {}.jpg .jpg`;

EDYCJA :

Rozwiązanie: pojedynczy cudzysłów zapobiega `basename ...`ocenie przez powłokę przed uruchomieniem polecenia.

ls *.sh | xargs -I {}  sh -c 'mv {} `basename {} .sh`'
majkinetor
źródło

Odpowiedzi:

12

Ponieważ polecenie basename jest uruchamiane przed uruchomieniem potoku. Aby to zadziałało, potrzebujesz xargs do wykonania basename i możesz to zrobić sh -c, np .:

ls *.sh | xargs -L1 sh -c 'basename $1 .sh' dummy

Uwagi:

  • Jeśli nie powiesz, xargsgdzie wstawić nazwy plików, zostaną one dodane na końcu wiersza poleceń.
  • Powinieneś użyć -L1przełącznika lub jego odpowiednika, więc xargsprzekazujesz tylko jeden argument do sh.
  • Korzystanie z wyjścia lsmoże mieć niepożądane efekty .

Edytować

Usunięto przestarzałe opcje, dzięki TechZilla

Thor
źródło
3
Twój pierwszy punkt jest nieprawidłowy, chyba że miałeś na myśli, że jest on domyślny w stosunku do -iopcji, ale te „klasyczne” opcje zostały wycofane. Na przykład, aby użyć tylko jednej opcji / linii, nowa strona podręcznika POSIX zaleca -L1. Aby wywołać stare zachowanie -i, strona zaleca tę -I'{}'opcję.
JM Becker
Tak naprawdę chodzi o symbole „” zamiast „”. Wydaje mi się, że zapobiega ocenie powłoki przez ``. Zobacz moje zmiany.
majkinetor
@TechZilla: dzięki za poprawki. @majkinetor: tak i nie, musisz opóźnić ocenę, ale nie sądzę, abyś mógł używać backticks (`).
Thor
1
@majkinetor: ah, rozumiem, co masz na myśli teraz. Aby zmienić nazwę plików w ten sposób, wolałbym użyć renamenp rename 's/\.sh//' *.sh. : Spróbuj najpierw z suchobiegiem ( -n).
Thor
1
@majkinetor: renamedziała świetnie i dość prosto, ale pamiętaj, że jest bardzo specyficzny dla dystrybucji. Dystrybucje oparte na RHEL i Debianie udostępniają różne renamepolecenia, dlatego należy o tym pamiętać podczas tworzenia skryptów między dystrybucjami.
JM Becker
4

Nie jestem pewien co do twojego pytania, czy faktycznie pytasz, dlaczego pierwsza linia nie działa? A może szukasz odpowiedniej metody zmiany nazwy wszystkich plików .sh?

Zakładając, że jest to najczystsza metoda, wolę wcześniej przygotować opcje poleceń xargs. Aby usunąć rozszerzenie pliku .sh, często rozważam takie podejście,

 find -maxdepth 1 -type f -iname '*.sh'  | sed 'p;s_.sh$__' | xargs -L2 mv
JM Becker
źródło