16

So I have a list of usernames such as:

user1
user2
user3

I want to apply id on each of them and get something like:

uid=100(user1) gid=5(g1) groups=5(g1),6(g6),7(g10)
.
.

How can I achieve this? Please note that the list is the output of another command say mycommand.

2
  • What input does mycommand expect? Or ismycommand a script of yours and you are asking how to give it the list of usernames as the input? Please edit and clarify.
    – dessert
    Dec 18, 2017 at 8:23
  • it's a script of mine that gives that list as output Dec 18, 2017 at 8:27

3 Answers 3

21

Use xargs:

mycommand | xargs -L1 id

Example:

$ (echo root; echo nobody) | xargs -L1 id
uid=0(root) gid=0(root) groups=0(root)
uid=65534(nobody) gid=65534(nogroup) groups=65534(nogroup)

You can also loop over the input in bash:

mycommand | while read line
do
    id "$line"
done

xargs converts input to arguments of a command. The -L1 option tells xargs to use each line as a sole argument to an invocation of the command.

3
  • 3
    If I know it is newline separated, and there is some danger that the input stream might contain spaces, I use '-d\n', as is: mycommand | xargs '-d\n' -L1 id Pretty much always a good idea, along with proper "$quoting" of all shell variables. Dec 18, 2017 at 17:34
  • @SethRobertson very true. I left off the -d '\n' and IFS= read -r since the input is said to be usernames, I felt it might be overkill.
    – Olorin
    Dec 19, 2017 at 1:01
  • Maybe more clear: echo -n "root nobody" | tr ' ' '\n' | xargs -L 1 id Apr 5, 2020 at 0:36
5

With bash, you can capture the lines of output into an array:

mapfile -t lines < <(mycommand)

And then iterate over them

for line in "${lines[@]}"; do
    id "$line"
done

This is not as concise as xargs, but if you need the lines for more than one thing, it's pretty useful.

2
  • what does ` < <` mean? Dec 18, 2017 at 11:39
  • 2
    The first < is the usual redirection of mapfile's stdin. <(...) is a process substitution -- process substitutions are very useful to avoid issues due to pipelines running in subshells. Dec 18, 2017 at 14:12
0
tar -czf reloads.stage.tgz $(find . | egrep "sh$|functions$|sql$|setup$")

First I tested the find/egrep to make sure I get the list I want, then I added it as a file list at the end of the tar command.

Hope this helps somewhat.

  1. find . just finds ALL the files under the current directory, though you could specify a subdirectory or a completely different path if you wish.
  2. egrep just allows for multiple grep search strings separated by a pipe (|).
  3. The rest should make sense after that.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .