12

Sometimes I use same foreach operation with different target files in csh.
If I can give foreach command in a single line, I could easily substitue the target file names to repeat the process.(I usually use `find . -name ...` for target files)
For the purpose of this question, let's assume I want to cat all the *.txt files.

$ foreach i (*.txt)
foreach? cat $i
foreach? end

I read https://unix.stackexchange.com/questions/32873/running-a-full-foreach-command and tried

alias disp 'echo "foreach i (*.txt)"; echo "cat "\$"i"; echo "end"; | /bin/csh'

when I type disp it gives me Invalid null command.
If I can do it in a single line, I could do !foreach:gs/\.c\>/.h/ (do the same replacing .c with .h). How can I do it?

Community
  • 1
  • 1
Chan Kim
  • 5,177
  • 12
  • 57
  • 112

5 Answers5

15

This method works for me:

printf 'foreach f ( 1 2 3 )\n echo $f \n end' | tcsh
miken32
  • 42,008
  • 16
  • 111
  • 154
Jonathan Gratus
  • 166
  • 1
  • 3
4

There is no easy way to do the foreach in one line under tcsh.

However, by using alias, you may get something very close to your question.

alias disp 'foreach i (*.txt)\
  cat $i\
end'

You can call disp in your terminal.

If you want to direct the result into a pipe, then echo `disp` | grep foobar.

Sometimes, we need to save the result first, before further processing: set foo=`disp`

TerrenceSun
  • 433
  • 3
  • 15
  • I like this answer better than the one that involves launching a child shell. The most common reason to want to do it in one line is for use as an alias and this solves it. – All The Rage Mar 04 '20 at 18:04
  • One down-side of this approach is that the history is messed up. It looks like: disp\n cat $i\n end\n – All The Rage Mar 04 '20 at 18:08
  • This is gold! My use case is to modify the current shell and this is perfect. I don't have the "messed up history" mentioned by @AllTheRage Thank you! – dado Feb 02 '23 at 00:31
0

Use bash -c:

$ bash -c 'for i in *.txt; do cat $i; done'

-1

For your first question, I don't know how to write this in .cshrc file directly.

But I will use another flexible way to do this.

1: Write a shell script: /home/user/disp.sh (or any path you want)

#/bin/bash
for line in `find . -name "*.c"`; do
echo ""
   cat "$line"
done

Or you only have csh shell:

#/bin/csh
foreach i (*.c)
    echo $i
end
  1. Add new alias command to the .cshrc file

    alias disp /home/user/disp.sh

  2. Reenter csh shell (or relogin)

    csh


For your second question, I did it on the same disp.sh script

This example is written in bash shell script.

#/bin/bash
usage() { echo "Usage: $0 [-d <depth>] [-e <extension>]" 1>&2; exit 1; }
while getopts ":d:e:" o; do
    case "${o}" in
        d)
            d=${OPTARG}
            ;;
        e)
            e=${OPTARG}
            ;;
        *)
            usage
            ;;
    esac
done
shift $((OPTIND-1))
if [ -z "${d}" ] || [ -z "${e}" ]; then
    usage
fi

for line in `find . -maxdepth ${d} -name "*.${e}"`; do
echo ""
   cat "$line"
done

You can simply type disp -d 1 -e c to find all .c file in the current path. (-d means the depth of the file which is started from current path, -e means extension of files)

Kir Chou
  • 2,980
  • 1
  • 36
  • 48
  • Hi, I think you didn't get the question right. I wanted to use the whole foreach command in single line so that I can substitute a part of it and run the command again easily. In bash, I can do simply `for i in 1 2 3; do echo $i; done` . – Chan Kim Aug 23 '16 at 02:37
-1

I tried to find answer but it looks there is no way. Just use bash by simply changing shell.

% bash

$ for f in *txt; do echo $f; done

$ exit

%

Joonho Park
  • 511
  • 5
  • 17